mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
refactor: remove old match v4 code + refactor command to v5
This commit is contained in:
parent
6c50339e94
commit
a7052b6f35
9 changed files with 17 additions and 649 deletions
|
|
@ -1,20 +1,20 @@
|
||||||
{
|
{
|
||||||
"commands": {
|
"commands": {
|
||||||
"load:v4": {
|
"load:matches": {
|
||||||
"settings": {
|
"settings": {
|
||||||
"loadApp": true,
|
"loadApp": true,
|
||||||
"stayAlive": false
|
"stayAlive": false
|
||||||
},
|
},
|
||||||
"commandPath": "./commands/LoadV4Matches",
|
"commandPath": "./commands/LoadMatches",
|
||||||
"commandName": "load:v4",
|
"commandName": "load:matches",
|
||||||
"description": "Load matches for a given Summoner from the old Match-V4 endpoint",
|
"description": "Load all possible matches for a given Summoner",
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"propertyName": "summoner",
|
"propertyName": "summoner",
|
||||||
"name": "summoner",
|
"name": "summoner",
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Summoner name to seach"
|
"description": "Summoner name to search"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
||||||
|
|
@ -1,242 +0,0 @@
|
||||||
import Database from '@ioc:Adonis/Lucid/Database'
|
|
||||||
import Match from 'App/Models/Match'
|
|
||||||
import { getSeasonNumber, notEmpty, PlayerRole, queuesWithRole, supportItems } from 'App/helpers'
|
|
||||||
import CDragonService from 'App/Services/CDragonService'
|
|
||||||
import { ChampionRoles, TeamPosition } from './ParsedType'
|
|
||||||
import { V4MatchDto } from 'App/Services/Jax/src/Endpoints/MatchV4Endpoint'
|
|
||||||
import RoleIdentificationService from 'App/Services/RoleIdentificationService'
|
|
||||||
import Jax from 'App/Services/Jax'
|
|
||||||
|
|
||||||
class MatchV4Parser {
|
|
||||||
public createMatchId(gameId: number, region: string) {
|
|
||||||
return `${region.toUpperCase()}_${gameId}`
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTeamRoles(team: PlayerRole[]) {
|
|
||||||
const teamJunglers = team.filter((p) => p.jungle && !p.support)
|
|
||||||
const jungle = teamJunglers.length === 1 ? teamJunglers[0].champion : undefined
|
|
||||||
const teamSupports = team.filter((p) => p.support && !p.jungle)
|
|
||||||
const support = teamSupports.length === 1 ? teamSupports[0].champion : undefined
|
|
||||||
|
|
||||||
return RoleIdentificationService.getRoles(
|
|
||||||
CDragonService.championRoles,
|
|
||||||
team.map((p) => p.champion),
|
|
||||||
jungle,
|
|
||||||
support
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getMatchRoles(match: V4MatchDto) {
|
|
||||||
const blueChamps: PlayerRole[] = []
|
|
||||||
const redChamps: PlayerRole[] = []
|
|
||||||
|
|
||||||
match.participants.map((p) => {
|
|
||||||
const items = [
|
|
||||||
p.stats.item0,
|
|
||||||
p.stats.item1,
|
|
||||||
p.stats.item2,
|
|
||||||
p.stats.item3,
|
|
||||||
p.stats.item4,
|
|
||||||
p.stats.item5,
|
|
||||||
]
|
|
||||||
const playerRole = {
|
|
||||||
champion: p.championId,
|
|
||||||
jungle: p.spell1Id === 11 || p.spell2Id === 11,
|
|
||||||
support: supportItems.some((suppItem) => items.includes(suppItem)),
|
|
||||||
}
|
|
||||||
p.teamId === 100 ? blueChamps.push(playerRole) : redChamps.push(playerRole)
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
blue: this.getTeamRoles(blueChamps),
|
|
||||||
red: this.getTeamRoles(redChamps),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async parseOneMatch(match: V4MatchDto) {
|
|
||||||
// Parse + store in database
|
|
||||||
const matchId = this.createMatchId(match.gameId, match.platformId)
|
|
||||||
console.log(matchId)
|
|
||||||
|
|
||||||
if (match.participants.length !== 10) {
|
|
||||||
console.log(`Match not saved because < 10 players. Gamemode: ${match.queueId}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// PUUID of the 10 players
|
|
||||||
const accountRequests = match.participantIdentities
|
|
||||||
.filter((p) => p.player.accountId !== '0')
|
|
||||||
.map((p) => Jax.Summoner.accountId(p.player.currentAccountId, match.platformId.toLowerCase()))
|
|
||||||
const playerAccounts = (await Promise.all(accountRequests)).filter(notEmpty)
|
|
||||||
|
|
||||||
if (!playerAccounts || !playerAccounts.length) {
|
|
||||||
console.log(`0 Account found from match: ${matchId}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRemake = match.gameDuration < 300
|
|
||||||
|
|
||||||
// Roles
|
|
||||||
const { blue: blueRoles, red: redRoles } = this.getMatchRoles(match)
|
|
||||||
|
|
||||||
// - 10x MatchPlayer
|
|
||||||
const matchPlayers: any[] = []
|
|
||||||
for (const player of match.participants) {
|
|
||||||
const identity = match.participantIdentities.find(
|
|
||||||
(p) => p.participantId === player.participantId
|
|
||||||
)!
|
|
||||||
const isBot = identity.player.accountId === '0'
|
|
||||||
const account = isBot
|
|
||||||
? null
|
|
||||||
: playerAccounts.find((p) => p.accountId === identity.player.currentAccountId)
|
|
||||||
|
|
||||||
if (!account && !isBot) {
|
|
||||||
console.log(`Account not found ${identity.player.currentAccountId}`)
|
|
||||||
console.log(`Match ${matchId} not saved in the database.`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const kda =
|
|
||||||
player.stats.kills + player.stats.assists !== 0 && player.stats.deaths === 0
|
|
||||||
? player.stats.kills + player.stats.assists
|
|
||||||
: +(
|
|
||||||
player.stats.deaths === 0
|
|
||||||
? 0
|
|
||||||
: (player.stats.kills + player.stats.assists) / player.stats.deaths
|
|
||||||
).toFixed(2)
|
|
||||||
|
|
||||||
const team = match.teams[0].teamId === player.teamId ? match.teams[0] : match.teams[1]
|
|
||||||
const totalKills = match.participants.reduce((prev, current) => {
|
|
||||||
if (current.teamId !== player.teamId) {
|
|
||||||
return prev
|
|
||||||
}
|
|
||||||
return prev + current.stats.kills
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
const kp =
|
|
||||||
totalKills === 0
|
|
||||||
? 0
|
|
||||||
: +(((player.stats.kills + player.stats.assists) * 100) / totalKills).toFixed(1)
|
|
||||||
|
|
||||||
// Perks
|
|
||||||
const primaryStyle = player.stats.perkPrimaryStyle
|
|
||||||
const secondaryStyle = player.stats.perkSubStyle
|
|
||||||
const perksSelected: number[] = []
|
|
||||||
for (let i = 0; i < 6; i++) {
|
|
||||||
perksSelected.push(player.stats[`perk${i}`])
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
perksSelected.push(player.stats[`statPerk${i}`])
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalChampionData = CDragonService.champions[player.championId]
|
|
||||||
const champRoles = originalChampionData.roles
|
|
||||||
|
|
||||||
// Role
|
|
||||||
const teamRoles = player.teamId === 100 ? blueRoles : redRoles
|
|
||||||
const role = Object.entries(teamRoles).find(
|
|
||||||
([, champion]) => player.championId === champion
|
|
||||||
)![0]
|
|
||||||
|
|
||||||
matchPlayers.push({
|
|
||||||
match_id: matchId,
|
|
||||||
participant_id: player.participantId,
|
|
||||||
summoner_id: isBot ? 'BOT' : identity.player.summonerId,
|
|
||||||
summoner_puuid: account ? account.puuid : 'BOT',
|
|
||||||
summoner_name: identity.player.summonerName,
|
|
||||||
win: team.win === 'Win' ? 1 : 0,
|
|
||||||
loss: team.win === 'Fail' ? 1 : 0,
|
|
||||||
remake: isRemake ? 1 : 0,
|
|
||||||
team: player.teamId,
|
|
||||||
team_position: queuesWithRole.includes(match.queueId)
|
|
||||||
? TeamPosition[role]
|
|
||||||
: TeamPosition.NONE,
|
|
||||||
kills: player.stats.kills,
|
|
||||||
deaths: player.stats.deaths,
|
|
||||||
assists: player.stats.assists,
|
|
||||||
kda: kda,
|
|
||||||
kp: kp,
|
|
||||||
champ_level: player.stats.champLevel,
|
|
||||||
champion_id: player.championId,
|
|
||||||
champion_role: ChampionRoles[champRoles[0]],
|
|
||||||
double_kills: player.stats.doubleKills,
|
|
||||||
triple_kills: player.stats.tripleKills,
|
|
||||||
quadra_kills: player.stats.quadraKills,
|
|
||||||
penta_kills: player.stats.pentaKills,
|
|
||||||
baron_kills: 0,
|
|
||||||
dragon_kills: 0,
|
|
||||||
turret_kills: player.stats.turretKills,
|
|
||||||
vision_score: player.stats.visionScore,
|
|
||||||
gold: player.stats.goldEarned,
|
|
||||||
summoner1_id: player.spell1Id,
|
|
||||||
summoner2_id: player.spell2Id,
|
|
||||||
item0: player.stats.item0,
|
|
||||||
item1: player.stats.item1,
|
|
||||||
item2: player.stats.item2,
|
|
||||||
item3: player.stats.item3,
|
|
||||||
item4: player.stats.item4,
|
|
||||||
item5: player.stats.item5,
|
|
||||||
item6: player.stats.item6,
|
|
||||||
damage_dealt_objectives: player.stats.damageDealtToObjectives,
|
|
||||||
damage_dealt_champions: player.stats.totalDamageDealtToChampions,
|
|
||||||
damage_taken: player.stats.totalDamageTaken,
|
|
||||||
heal: player.stats.totalHeal,
|
|
||||||
minions: player.stats.totalMinionsKilled + player.stats.neutralMinionsKilled,
|
|
||||||
critical_strike: player.stats.largestCriticalStrike,
|
|
||||||
killing_spree: player.stats.killingSprees,
|
|
||||||
time_spent_living: player.stats.longestTimeSpentLiving,
|
|
||||||
perks_primary_style: primaryStyle ?? 8100,
|
|
||||||
perks_secondary_style: secondaryStyle ?? 8000,
|
|
||||||
perks_selected: perksSelected,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
await Database.table('match_players').multiInsert(matchPlayers)
|
|
||||||
|
|
||||||
// - 1x Match
|
|
||||||
const parsedMatch = await Match.create({
|
|
||||||
id: matchId,
|
|
||||||
gameId: match.gameId,
|
|
||||||
map: match.mapId,
|
|
||||||
gamemode: match.queueId,
|
|
||||||
date: match.gameCreation,
|
|
||||||
region: match.platformId.toLowerCase(),
|
|
||||||
result: match.teams[0].win === 'Win' ? match.teams[0].teamId : match.teams[1].teamId,
|
|
||||||
season: getSeasonNumber(match.gameCreation),
|
|
||||||
gameDuration: match.gameDuration,
|
|
||||||
})
|
|
||||||
|
|
||||||
// - 2x MatchTeam : Red and Blue
|
|
||||||
for (const team of match.teams) {
|
|
||||||
let result = team.win === 'Win' ? 'Win' : 'Fail'
|
|
||||||
if (isRemake) {
|
|
||||||
result = 'Remake'
|
|
||||||
}
|
|
||||||
await parsedMatch.related('teams').create({
|
|
||||||
matchId: matchId,
|
|
||||||
color: team.teamId,
|
|
||||||
result: result,
|
|
||||||
barons: team.baronKills,
|
|
||||||
dragons: team.dragonKills,
|
|
||||||
inhibitors: team.inhibitorKills,
|
|
||||||
riftHeralds: team.riftHeraldKills,
|
|
||||||
towers: team.towerKills,
|
|
||||||
bans: team.bans.length ? team.bans.map((ban) => ban.championId) : undefined,
|
|
||||||
banOrders: team.bans.length ? team.bans.map((ban) => ban.pickTurn) : undefined,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return parsedMatch
|
|
||||||
}
|
|
||||||
|
|
||||||
public async parse(matches: V4MatchDto[]) {
|
|
||||||
// Loop on all matches and call .parseOneMatch on it
|
|
||||||
const parsedMatches: Match[] = []
|
|
||||||
for (const match of matches) {
|
|
||||||
const parsed = await this.parseOneMatch(match)
|
|
||||||
if (parsed) {
|
|
||||||
parsedMatches.push(parsed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parsedMatches.length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new MatchV4Parser()
|
|
||||||
|
|
@ -1,240 +0,0 @@
|
||||||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
|
||||||
import RiotRateLimiter from 'riot-ratelimiter'
|
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
|
||||||
import JaxRequest from '../JaxRequest'
|
|
||||||
|
|
||||||
export interface V4MatchDto {
|
|
||||||
gameId: number
|
|
||||||
participantIdentities: V4ParticipantIdentityDto[]
|
|
||||||
queueId: number
|
|
||||||
gameType: string
|
|
||||||
gameDuration: number
|
|
||||||
teams: V4TeamStatsDto[]
|
|
||||||
platformId: string
|
|
||||||
gameCreation: number
|
|
||||||
seasonId: number
|
|
||||||
gameVersion: string
|
|
||||||
mapId: number
|
|
||||||
gameMode: string
|
|
||||||
participants: V4ParticipantDto[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4ParticipantIdentityDto {
|
|
||||||
participantId: number
|
|
||||||
player: V4PlayerDto
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4PlayerDto {
|
|
||||||
profileIcon: number
|
|
||||||
accountId: string
|
|
||||||
matchHistoryUri: string
|
|
||||||
currentAccountId: string
|
|
||||||
currentPlatformId: string
|
|
||||||
summonerName: string
|
|
||||||
summonerId: string
|
|
||||||
platformId: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4TeamStatsDto {
|
|
||||||
towerKills: number
|
|
||||||
riftHeraldKills: number
|
|
||||||
firstBlood: boolean
|
|
||||||
inhibitorKills: number
|
|
||||||
bans: V4TeamBansDto[]
|
|
||||||
firstBaron: boolean
|
|
||||||
firstDragon: boolean
|
|
||||||
dominionVictoryScore: number
|
|
||||||
dragonKills: number
|
|
||||||
baronKills: number
|
|
||||||
firstInhibitor: boolean
|
|
||||||
firstTower: boolean
|
|
||||||
vilemawKills: number
|
|
||||||
firstRiftHerald: boolean
|
|
||||||
teamId: number // 100 for blue side. 200 for red side.
|
|
||||||
win: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4TeamBansDto {
|
|
||||||
championId: number
|
|
||||||
pickTurn: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4ParticipantDto {
|
|
||||||
participantId: number
|
|
||||||
championId: number
|
|
||||||
runes: V4RuneDto[]
|
|
||||||
stats: V4ParticipantStatsDto
|
|
||||||
teamId: number
|
|
||||||
timeline: V4ParticipantTimelineDto
|
|
||||||
spell1Id: number
|
|
||||||
spell2Id: number
|
|
||||||
highestAchievedSeasonTier?:
|
|
||||||
| 'CHALLENGER'
|
|
||||||
| 'MASTER'
|
|
||||||
| 'DIAMOND'
|
|
||||||
| 'PLATINUM'
|
|
||||||
| 'GOLD'
|
|
||||||
| 'SILVER'
|
|
||||||
| 'BRONZE'
|
|
||||||
| 'UNRANKED'
|
|
||||||
masteries: V4MasteryDto[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4RuneDto {
|
|
||||||
runeId: number
|
|
||||||
rank: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4ParticipantStatsDto {
|
|
||||||
item0: number
|
|
||||||
item2: number
|
|
||||||
totalUnitsHealed: number
|
|
||||||
item1: number
|
|
||||||
largestMultiKill: number
|
|
||||||
goldEarned: number
|
|
||||||
firstInhibitorKill: boolean
|
|
||||||
physicalDamageTaken: number
|
|
||||||
nodeNeutralizeAssist: number
|
|
||||||
totalPlayerScore: number
|
|
||||||
champLevel: number
|
|
||||||
damageDealtToObjectives: number
|
|
||||||
totalDamageTaken: number
|
|
||||||
neutralMinionsKilled: number
|
|
||||||
deaths: number
|
|
||||||
tripleKills: number
|
|
||||||
magicDamageDealtToChampions: number
|
|
||||||
wardsKilled: number
|
|
||||||
pentaKills: number
|
|
||||||
damageSelfMitigated: number
|
|
||||||
largestCriticalStrike: number
|
|
||||||
nodeNeutralize: number
|
|
||||||
totalTimeCrowdControlDealt: number
|
|
||||||
firstTowerKill: boolean
|
|
||||||
magicDamageDealt: number
|
|
||||||
totalScoreRank: number
|
|
||||||
nodeCapture: number
|
|
||||||
wardsPlaced: number
|
|
||||||
totalDamageDealt: number
|
|
||||||
timeCCingOthers: number
|
|
||||||
magicalDamageTaken: number
|
|
||||||
largestKillingSpree: number
|
|
||||||
totalDamageDealtToChampions: number
|
|
||||||
physicalDamageDealtToChampions: number
|
|
||||||
neutralMinionsKilledTeamJungle: number
|
|
||||||
totalMinionsKilled: number
|
|
||||||
firstInhibitorAssist: boolean
|
|
||||||
visionWardsBoughtInGame: number
|
|
||||||
objectivePlayerScore: number
|
|
||||||
kills: number
|
|
||||||
firstTowerAssist: boolean
|
|
||||||
combatPlayerScore: number
|
|
||||||
inhibitorKills: number
|
|
||||||
turretKills: number
|
|
||||||
participantId: number
|
|
||||||
trueDamageTaken: number
|
|
||||||
firstBloodAssist: boolean
|
|
||||||
nodeCaptureAssist: number
|
|
||||||
assists: number
|
|
||||||
teamObjective: number
|
|
||||||
altarsNeutralized: number
|
|
||||||
goldSpent: number
|
|
||||||
damageDealtToTurrets: number
|
|
||||||
altarsCaptured: number
|
|
||||||
win: boolean
|
|
||||||
totalHeal: number
|
|
||||||
unrealKills: number
|
|
||||||
visionScore: number
|
|
||||||
physicalDamageDealt: number
|
|
||||||
firstBloodKill: boolean
|
|
||||||
longestTimeSpentLiving: number
|
|
||||||
killingSprees: number
|
|
||||||
sightWardsBoughtInGame: number
|
|
||||||
trueDamageDealtToChampions: number
|
|
||||||
neutralMinionsKilledEnemyJungle: number
|
|
||||||
doubleKills: number
|
|
||||||
trueDamageDealt: number
|
|
||||||
quadraKills: number
|
|
||||||
item4: number
|
|
||||||
item3: number
|
|
||||||
item6: number
|
|
||||||
item5: number
|
|
||||||
playerScore0: number
|
|
||||||
playerScore1: number
|
|
||||||
playerScore2: number
|
|
||||||
playerScore3: number
|
|
||||||
playerScore4: number
|
|
||||||
playerScore5: number
|
|
||||||
playerScore6: number
|
|
||||||
playerScore7: number
|
|
||||||
playerScore8: number
|
|
||||||
playerScore9: number
|
|
||||||
perk0: number
|
|
||||||
perk0Var1: number
|
|
||||||
perk0Var2: number
|
|
||||||
perk0Var3: number
|
|
||||||
perk1: number
|
|
||||||
perk1Var1: number
|
|
||||||
perk1Var2: number
|
|
||||||
perk1Var3: number
|
|
||||||
perk2: number
|
|
||||||
perk2Var1: number
|
|
||||||
perk2Var2: number
|
|
||||||
perk2Var3: number
|
|
||||||
perk3: number
|
|
||||||
perk3Var1: number
|
|
||||||
perk3Var2: number
|
|
||||||
perk3Var3: number
|
|
||||||
perk4: number
|
|
||||||
perk4Var1: number
|
|
||||||
perk4Var2: number
|
|
||||||
perk4Var3: number
|
|
||||||
perk5: number
|
|
||||||
perk5Var1: number
|
|
||||||
perk5Var2: number
|
|
||||||
perk5Var3: number
|
|
||||||
perkPrimaryStyle: number
|
|
||||||
perkSubStyle: number
|
|
||||||
statPerk0: number
|
|
||||||
statPerk1: number
|
|
||||||
statPerk2: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4ParticipantTimelineDto {
|
|
||||||
participantId: number
|
|
||||||
csDiffPerMinDeltas: { [index: string]: number }
|
|
||||||
damageTakenPerMinDeltas: { [index: string]: number }
|
|
||||||
role: 'DUO' | 'NONE' | 'SOLO' | 'DUO_CARRY' | 'DUO_SUPPORT'
|
|
||||||
damageTakenDiffPerMinDeltas: { [index: string]: number }
|
|
||||||
xpPerMinDeltas: { [index: string]: number }
|
|
||||||
xpDiffPerMinDeltas: { [index: string]: number }
|
|
||||||
lane: 'MID' | 'MIDDLE' | 'TOP' | 'JUNGLE' | 'BOT' | 'BOTTOM'
|
|
||||||
creepsPerMinDeltas: { [index: string]: number }
|
|
||||||
goldPerMinDeltas: { [index: string]: number }
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4MasteryDto {
|
|
||||||
rank: number
|
|
||||||
masteryId: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class MatchV4Endpoint {
|
|
||||||
private config: JaxConfig
|
|
||||||
private limiter: RiotRateLimiter
|
|
||||||
|
|
||||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
|
||||||
this.config = config
|
|
||||||
this.limiter = limiter
|
|
||||||
|
|
||||||
this.get = this.get.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(matchID: number, region: string): Promise<V4MatchDto> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`match/v4/matches/${matchID}`,
|
|
||||||
this.limiter,
|
|
||||||
1500
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
|
||||||
import RiotRateLimiter from 'riot-ratelimiter'
|
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
|
||||||
import JaxRequest from '../JaxRequest'
|
|
||||||
|
|
||||||
export interface V4MatchlistDto {
|
|
||||||
startIndex: number
|
|
||||||
totalGames: number
|
|
||||||
endIndex: number
|
|
||||||
matches: V4MatchReferenceDto[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface V4MatchReferenceDto {
|
|
||||||
gameId: number
|
|
||||||
role: string
|
|
||||||
season: number
|
|
||||||
platformId: string
|
|
||||||
champion: number
|
|
||||||
queue: number
|
|
||||||
lane: string
|
|
||||||
timestamp: number
|
|
||||||
seasonMatch?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class MatchlistV4Endpoint {
|
|
||||||
private config: JaxConfig
|
|
||||||
private limiter: RiotRateLimiter
|
|
||||||
|
|
||||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
|
||||||
this.config = config
|
|
||||||
this.limiter = limiter
|
|
||||||
}
|
|
||||||
|
|
||||||
public accountID(accountID: string, region: string, beginIndex = 0): Promise<V4MatchlistDto> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`match/v4/matchlists/by-account/${accountID}?beginIndex=${beginIndex}`,
|
|
||||||
this.limiter,
|
|
||||||
0
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,10 +3,8 @@ import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
import JaxRequest from '../JaxRequest'
|
||||||
|
|
||||||
export interface SummonerDTO {
|
export interface SummonerDTO {
|
||||||
accountId: string
|
|
||||||
profileIconId: number
|
profileIconId: number
|
||||||
revisionDate: number
|
revisionDate: number
|
||||||
id: string
|
|
||||||
puuid: string
|
puuid: string
|
||||||
summonerLevel: number
|
summonerLevel: number
|
||||||
}
|
}
|
||||||
|
|
@ -25,36 +23,6 @@ export default class SummonerEndpoint {
|
||||||
this.limiter = limiter
|
this.limiter = limiter
|
||||||
}
|
}
|
||||||
|
|
||||||
public accountId(accountId: string, region: string): Promise<SummonerDTO> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`summoner/v4/summoners/by-account/${accountId}`,
|
|
||||||
this.limiter,
|
|
||||||
36000
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
|
|
||||||
public summonerId(summonerId: string, region: string): Promise<SummonerDTO> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`summoner/v4/summoners/${summonerId}`,
|
|
||||||
this.limiter,
|
|
||||||
36000
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
|
|
||||||
public summonerName(summonerName: string, region: string): Promise<SummonerDTO> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`summoner/v4/summoners/by-name/${encodeURI(summonerName)}`,
|
|
||||||
this.limiter,
|
|
||||||
36000
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
|
|
||||||
public summonerPuuid(puuid: string, region: string): Promise<SummonerDTO> {
|
public summonerPuuid(puuid: string, region: string): Promise<SummonerDTO> {
|
||||||
return new JaxRequest(
|
return new JaxRequest(
|
||||||
region,
|
region,
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ import CDragonEndpoint from './Endpoints/CDragonEndpoint'
|
||||||
import { JaxConfig } from '../JaxConfig'
|
import { JaxConfig } from '../JaxConfig'
|
||||||
import RiotRateLimiter from 'riot-ratelimiter'
|
import RiotRateLimiter from 'riot-ratelimiter'
|
||||||
import { STRATEGY } from 'riot-ratelimiter/dist/RateLimiter'
|
import { STRATEGY } from 'riot-ratelimiter/dist/RateLimiter'
|
||||||
import MatchV4Endpoint from './Endpoints/MatchV4Endpoint'
|
|
||||||
import MatchlistV4Endpoint from './Endpoints/MatchlistV4Endpoint'
|
|
||||||
|
|
||||||
export default class Jax {
|
export default class Jax {
|
||||||
public key: string
|
public key: string
|
||||||
|
|
@ -18,9 +16,7 @@ export default class Jax {
|
||||||
public Account: AccountEndpoint
|
public Account: AccountEndpoint
|
||||||
public League: LeagueEndpoint
|
public League: LeagueEndpoint
|
||||||
public Match: MatchEndpoint
|
public Match: MatchEndpoint
|
||||||
public MatchV4: MatchV4Endpoint
|
|
||||||
public Matchlist: MatchlistEndpoint
|
public Matchlist: MatchlistEndpoint
|
||||||
public MatchlistV4: MatchlistV4Endpoint
|
|
||||||
public Spectator: SpectatorEndpoint
|
public Spectator: SpectatorEndpoint
|
||||||
public Summoner: SummonerEndpoint
|
public Summoner: SummonerEndpoint
|
||||||
public CDragon: CDragonEndpoint
|
public CDragon: CDragonEndpoint
|
||||||
|
|
@ -40,9 +36,7 @@ export default class Jax {
|
||||||
this.Account = new AccountEndpoint(this.config, this.limiter)
|
this.Account = new AccountEndpoint(this.config, this.limiter)
|
||||||
this.League = new LeagueEndpoint(this.config, this.limiter)
|
this.League = new LeagueEndpoint(this.config, this.limiter)
|
||||||
this.Match = new MatchEndpoint(this.config, this.limiter)
|
this.Match = new MatchEndpoint(this.config, this.limiter)
|
||||||
this.MatchV4 = new MatchV4Endpoint(this.config, this.limiter)
|
|
||||||
this.Matchlist = new MatchlistEndpoint(this.config, this.limiter)
|
this.Matchlist = new MatchlistEndpoint(this.config, this.limiter)
|
||||||
this.MatchlistV4 = new MatchlistV4Endpoint(this.config, this.limiter)
|
|
||||||
this.Spectator = new SpectatorEndpoint(this.config, this.limiter)
|
this.Spectator = new SpectatorEndpoint(this.config, this.limiter)
|
||||||
this.Summoner = new SummonerEndpoint(this.config, this.limiter)
|
this.Summoner = new SummonerEndpoint(this.config, this.limiter)
|
||||||
this.CDragon = new CDragonEndpoint(this.config)
|
this.CDragon = new CDragonEndpoint(this.config)
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,7 @@ export default class JaxRequest {
|
||||||
!this.endpoint.includes('match/v4/matchlists/by-account')
|
!this.endpoint.includes('match/v4/matchlists/by-account')
|
||||||
) {
|
) {
|
||||||
Logger.error(`URL ${url}: `)
|
Logger.error(`URL ${url}: `)
|
||||||
console.log('JAX ERROR')
|
console.log('JAX ERROR', statusCode, rest?.cause?.code)
|
||||||
console.log(rest?.cause?.code)
|
|
||||||
// Logger.error(`JaxRequest Error ${statusCode}: `, rest)
|
// Logger.error(`JaxRequest Error ${statusCode}: `, rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import Jax from './Jax'
|
|
||||||
import { getSeasonNumber, notEmpty } from 'App/helpers'
|
|
||||||
import { V4MatchReferenceDto } from './Jax/src/Endpoints/MatchlistV4Endpoint'
|
|
||||||
import { SummonerDTO } from './Jax/src/Endpoints/SummonerEndpoint'
|
|
||||||
import MatchV4Parser from 'App/Parsers/MatchV4Parser'
|
|
||||||
import Match from 'App/Models/Match'
|
|
||||||
|
|
||||||
class MatchService {
|
|
||||||
private async _fetchMatchListUntil(account: SummonerDTO, region: string) {
|
|
||||||
let matchList: V4MatchReferenceDto[] = []
|
|
||||||
let alreadyIn = false
|
|
||||||
let index = 0
|
|
||||||
do {
|
|
||||||
let newMatchList = await Jax.MatchlistV4.accountID(account.accountId, region, index)
|
|
||||||
// Error while fetching Riot API
|
|
||||||
if (!newMatchList) {
|
|
||||||
matchList = matchList.map((m) => {
|
|
||||||
m.seasonMatch = getSeasonNumber(m.timestamp)
|
|
||||||
return m
|
|
||||||
})
|
|
||||||
return matchList
|
|
||||||
}
|
|
||||||
matchList = [...matchList, ...newMatchList.matches]
|
|
||||||
alreadyIn = newMatchList.matches.length === 0
|
|
||||||
// If the match is made in another region : we stop fetching
|
|
||||||
if (matchList[matchList.length - 1].platformId.toLowerCase() !== region) {
|
|
||||||
alreadyIn = true
|
|
||||||
}
|
|
||||||
index += 100
|
|
||||||
} while (!alreadyIn)
|
|
||||||
|
|
||||||
// Remove matches from MatchList made in another region, tutorial games, 3v3 games, Coop vs IA games
|
|
||||||
const tutorialModes = [2000, 2010, 2020, 460, 470, 800, 810, 820, 830, 840, 850]
|
|
||||||
matchList = matchList
|
|
||||||
.filter((m) => {
|
|
||||||
const sameRegion = m.platformId.toLowerCase() === region
|
|
||||||
const notATutorialGame = !tutorialModes.includes(m.queue)
|
|
||||||
|
|
||||||
return sameRegion && notATutorialGame
|
|
||||||
})
|
|
||||||
.map((m) => {
|
|
||||||
m.seasonMatch = getSeasonNumber(m.timestamp)
|
|
||||||
return m
|
|
||||||
})
|
|
||||||
|
|
||||||
return matchList
|
|
||||||
}
|
|
||||||
|
|
||||||
public async updateMatchList(account: SummonerDTO, region: string) {
|
|
||||||
return this._fetchMatchListUntil(account, region)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getMatches(region: string, matchlist: V4MatchReferenceDto[]) {
|
|
||||||
const matchesToGetFromRiot: number[] = []
|
|
||||||
for (const match of matchlist) {
|
|
||||||
const matchSaved = await Match.query()
|
|
||||||
.where('id', MatchV4Parser.createMatchId(match.gameId, region))
|
|
||||||
.first()
|
|
||||||
if (!matchSaved) {
|
|
||||||
matchesToGetFromRiot.push(match.gameId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const requests = matchesToGetFromRiot.map((gameId) => Jax.MatchV4.get(gameId, region))
|
|
||||||
const matchesFromApi = await Promise.all(requests)
|
|
||||||
const filteredMatches = matchesFromApi.filter(notEmpty)
|
|
||||||
|
|
||||||
return filteredMatches.length ? await MatchV4Parser.parse(filteredMatches) : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new MatchService()
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import { BaseCommand, args } from '@adonisjs/core/build/standalone'
|
import { BaseCommand, args } from '@adonisjs/core/build/standalone'
|
||||||
import MatchV4Service from 'App/Services/MatchV4Service'
|
import MatchService, { MatchListMode } from 'App/Services/MatchService'
|
||||||
import SummonerService from 'App/Services/SummonerService'
|
import SummonerService from 'App/Services/SummonerService'
|
||||||
|
|
||||||
export default class LoadV4Matches extends BaseCommand {
|
export default class LoadMatches extends BaseCommand {
|
||||||
/**
|
/**
|
||||||
* Command name is used to run the command
|
* Command name is used to run the command
|
||||||
*/
|
*/
|
||||||
public static commandName = 'load:v4'
|
public static commandName = 'load:matches'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command description is displayed in the "help" output
|
* Command description is displayed in the "help" output
|
||||||
*/
|
*/
|
||||||
public static description = 'Load matches for a given Summoner from the old Match-V4 endpoint'
|
public static description = 'Load all possible matches for a given Summoner'
|
||||||
|
|
||||||
@args.string({ description: 'Summoner name to seach' })
|
@args.string({ description: 'Summoner name to search' })
|
||||||
public summoner: string
|
public summoner: string
|
||||||
|
|
||||||
@args.string({ description: 'League region of the summoner' })
|
@args.string({ description: 'League region of the summoner' })
|
||||||
|
|
@ -45,7 +45,11 @@ export default class LoadV4Matches extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MATCHLIST
|
// MATCHLIST
|
||||||
const matchListIds = await MatchV4Service.updateMatchList(account, this.region)
|
const matchListIds = await MatchService.updateMatchList(
|
||||||
|
account.puuid,
|
||||||
|
this.region,
|
||||||
|
MatchListMode.FIRSTIME
|
||||||
|
)
|
||||||
if (matchListIds.length) {
|
if (matchListIds.length) {
|
||||||
this.logger.success(`${matchListIds.length} matches in the matchlist.`)
|
this.logger.success(`${matchListIds.length} matches in the matchlist.`)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -57,7 +61,7 @@ export default class LoadV4Matches extends BaseCommand {
|
||||||
let savedMatches = 0
|
let savedMatches = 0
|
||||||
for (let i = 0; i < matchListIds.length; i += chunkSize) {
|
for (let i = 0; i < matchListIds.length; i += chunkSize) {
|
||||||
const chunk = matchListIds.slice(i, i + chunkSize)
|
const chunk = matchListIds.slice(i, i + chunkSize)
|
||||||
savedMatches += await MatchV4Service.getMatches(this.region, chunk)
|
savedMatches += (await MatchService.getMatches(this.region, chunk, account.puuid)).length
|
||||||
this.logger.info(`${savedMatches} matches saved.`)
|
this.logger.info(`${savedMatches} matches saved.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue