Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add player/records endpoint #1839

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
32 changes: 32 additions & 0 deletions routes/recordFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = [
'kills',
'actions_per_min',
'assists',
'comeback',
'courier_kills',
'deaths',
'denies',
'duration',
'lane_efficiency_pct',
'purchase_gem',
'gold_per_min',
'hero_damage',
'hero_healing',
'kda',
'last_hits',
'level',
'loss',
'pings',
'neutral_kills',
'purchase_ward_observer',
'purchase_rapier',
'purchase_ward_sentry',
'stomp',
'stuns',
'throw',
'tower_damage',
'tower_kills',
'purchase_tpscroll',
'win_rate',
'xp_per_min',
];
139 changes: 139 additions & 0 deletions routes/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,14 @@ The OpenDota API provides Dota 2 related data including advanced match data extr
description: 'personaname',
type: 'string',
},
name: {
description: 'name',
type: 'string',
},
is_contributor: {
description: 'is_contributor',
type: 'boolean',
},
last_login: {
description: 'last_login',
type: 'string',
Expand Down Expand Up @@ -2121,6 +2129,137 @@ The OpenDota API provides Dota 2 related data including advanced match data extr
},
},
},
'/players/{account_id}/records': {
get: {
summary: 'GET /players/{account_id}/records',
description: 'Player records',
tags: [
'players',
],
parameters: [params.accountIdParam],
responses: {
200: {
description: 'Success',
schema: {
type: 'object',
properties: {
hero_healing: {
type: 'object',
properties: {
hero_healing: {
description: 'hero_healing',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
gold_per_min: {
type: 'object',
properties: {
gold_per_min: {
description: 'gold_per_min',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
kda: {
type: 'object',
properties: {
kda: {
description: 'kda',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
last_hits: {
type: 'object',
properties: {
last_hits: {
description: 'last_hits',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
neutral_kills: {
type: 'object',
properties: {
neutral_kills: {
description: 'neutral_kills',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
pings: {
type: 'object',
properties: {
pings: {
description: 'pings',
type: 'integer',
},
hero_id: {
description: 'hero_id',
type: 'integer',
},
start_time: {
description: 'start_time',
type: 'integer',
},
},
},
},
},
},
},
route: () => '/players/:account_id/records',
func: (req, res, cb) => {
queries.getPlayerRecords(req.params.account_id, (err, records) => {
if (err) {
return cb(err);
}
return res.json(records);
});
},
},
},
'/players/{account_id}/refresh': {
post: {
summary: 'POST /players/{account_id}/refresh',
Expand Down
55 changes: 43 additions & 12 deletions store/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ const { es, INDEX } = require('../store/elasticsearch');
const cassandra = require('../store/cassandra');
const cacheFunctions = require('./cacheFunctions');
const benchmarksUtil = require('../util/benchmarksUtil');
const recordFields = require('../routes/recordFields');

const {
redisCount, convert64to32, serialize, deserialize, isRadiant,
redisCount, convert64to32, serialize, deserialize, isRadiant, isContributor,
} = utility;
const { computeMatchData } = compute;
const columnInfo = {};
Expand Down Expand Up @@ -376,18 +377,24 @@ function getPeers(db, input, player, cb) {
// limit to 200 max players
teammatesArr = teammatesArr.slice(0, 200);
return async.each(teammatesArr, (t, cb) => {
db.first().from('players').where({
account_id: t.account_id,
}).asCallback((err, row) => {
if (err || !row) {
db.first('players.account_id', 'personaname', 'name', 'avatar', 'avatarfull')
builder-247 marked this conversation as resolved.
Show resolved Hide resolved
.from('players')
.leftJoin('notable_players', 'players.account_id', 'notable_players.account_id')
.where({
'players.account_id': t.account_id,
})
.asCallback((err, row) => {
if (err || !row) {
return cb(err);
}
t.personaname = row.personaname;
t.name = row.name;
t.is_contributor = isContributor(t.account_id);
t.last_login = row.last_login;
t.avatar = row.avatar;
t.avatarfull = row.avatarfull;
return cb(err);
}
t.personaname = row.personaname;
t.last_login = row.last_login;
t.avatar = row.avatar;
t.avatarfull = row.avatarfull;
return cb(err);
});
});
}, (err) => {
cb(err, teammatesArr);
});
Expand Down Expand Up @@ -451,6 +458,29 @@ function getMatchRankTier(match, cb) {
});
}

function getPlayerRecords(player, cb) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to have to be cached in some way. . . otherwise this one call is making 20+ calls to the database

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I should only call the getPlayerMatches function once and then sort the data from there? Or do you have other ideas how this should be handled?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that might be more efficient.

const obj = {};
async.each(recordFields, (field, done) => {
const queryObj = {
sort: field,
limit: 1,
project: [field, 'hero_id', 'start_time'],
};
getPlayerMatches(player, queryObj, (err, cache) => {
if (err) {
return cb(err);
}
[obj[field]] = cache;
return done();
});
}, (err) => {
if (err) {
return cb(err);
}
return cb(null, obj);
});
}

function upsert(db, table, row, conflict, cb) {
cleanRowPostgres(db, table, row, (err, row) => {
if (err) {
Expand Down Expand Up @@ -1175,6 +1205,7 @@ module.exports = {
getPlayerMatches,
getPlayerRatings,
getPlayerHeroRankings,
getPlayerRecords,
getPlayer,
getMmrEstimate,
getPeers,
Expand Down