feat: add Jax Service back

This commit is contained in:
Kalane 2021-09-12 16:21:20 +02:00
parent 753bda3418
commit 63b42f7c86
15 changed files with 2535 additions and 21 deletions

View file

@ -0,0 +1,21 @@
import Env from '@ioc:Adonis/Core/Env'
export interface JaxConfig {
key: string
region: string
requestOptions: JaxConfigRequestOptions
}
export interface JaxConfigRequestOptions {
retriesBeforeAbort: number
delayBeforeRetry: number
}
export const JAX_CONFIG: JaxConfig = {
key: Env.get('API_KEY') as string,
region: 'euw1',
requestOptions: {
retriesBeforeAbort: 3,
delayBeforeRetry: 1000,
},
}

View file

@ -0,0 +1,4 @@
import Jax from './src/Jax'
import { JAX_CONFIG } from './JaxConfig'
export = new Jax(JAX_CONFIG)

View file

@ -0,0 +1,53 @@
import { promisify } from 'util'
import got from 'got'
import Logger from '@ioc:Adonis/Core/Logger'
import Redis from '@ioc:Adonis/Addons/Redis'
import { JaxConfig } from '../JaxConfig'
export default class CDragonRequest {
private config: JaxConfig
private endpoint: string
private cacheTime: number
private retries: number
private sleep: { (ms: number): Promise<void>; <T>(ms: number, value: T): Promise<T> }
constructor(config: JaxConfig, endpoint: string, cacheTime: number) {
this.config = config
this.endpoint = endpoint
this.cacheTime = cacheTime
this.retries = config.requestOptions.retriesBeforeAbort
this.sleep = promisify(setTimeout)
}
// https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/items.json
// https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/perks.json
// https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/perkstyles.json
// https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json
// https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/summoner-spells.json
public async execute() {
const url = `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/${this.endpoint}`
const requestCached = await Redis.get(url)
if (requestCached) {
return JSON.parse(requestCached)
}
try {
const response = await got(url)
await Redis.set(url, response.body, 'EX', this.cacheTime)
return JSON.parse(response.body)
} catch (error) {
this.retries--
Logger.error('CDragon Error : ', error)
if (this.retries > 0) {
await this.sleep(this.config.requestOptions.delayBeforeRetry)
return this.execute()
}
}
}
}

View file

@ -0,0 +1,104 @@
import { JaxConfig } from '../../JaxConfig'
import CDragonRequest from '../CDragonRequest'
export interface ChampionDTO {
id: number
name: string
alias: string
squarePortraitPath: string
roles: string[]
}
export interface ItemDTO {
id: number
name: string
description: string
active: boolean
inStore: boolean
from: number[]
to: number[]
categories: string[]
mapStringIdInclusions: string[]
maxStacks: number
modeNameInclusions: string[]
requiredChampion: string
requiredAlly: string
requiredBuffCurrencyName: string
requiredBuffCurrencyCost: number
specialRecipe: number
isEnchantment: boolean
price: number
priceTotal: number
iconPath: string
}
export interface PerkDTO {
id: number
name: string
majorChangePatchVersion: string
tooltip: string
shortDesc: string
longDesc: string
iconPath: string
endOfGameStatDescs: string[]
}
export interface PerkStyleResponse {
schemaVersion: string
styles: PerkStyleDTO[]
}
export interface PerkStyleDTO {
id: number
name: string
tooltip: string
iconPath: string
assetMap: { [key: string]: string }
isAdvanced: boolean
allowedSubStyles: number[]
subStyleBonus: { styleId: number; perkId: number }[]
slots: { type: string; slotLabel: string; perks: number[] }[]
defaultPageName: string
defaultSubStyle: number
defaultPerks: number[]
defaultPerksWhenSplashed: number[]
defaultStatModsPerSubStyle: { id: string; perks: number[] }[]
}
export interface SummonerSpellDTO {
id: number
name: string
description: string
summonerLevel: number
cooldown: number
gameModes: string[]
iconPath: string
}
export default class CDragonEndpoint {
private config: JaxConfig
constructor(config: JaxConfig) {
this.config = config
}
public async champions(): Promise<ChampionDTO[]> {
return new CDragonRequest(this.config, 'champion-summary.json', 36000).execute()
}
public async items(): Promise<ItemDTO[]> {
return new CDragonRequest(this.config, 'items.json', 36000).execute()
}
public async perks(): Promise<PerkDTO[]> {
return new CDragonRequest(this.config, 'perks.json', 36000).execute()
}
public async perkstyles(): Promise<PerkStyleResponse> {
return new CDragonRequest(this.config, 'perkstyles.json', 36000).execute()
}
public async summonerSpells(): Promise<SummonerSpellDTO[]> {
return new CDragonRequest(this.config, 'summoner-spells.json', 36000).execute()
}
}

View file

@ -0,0 +1,48 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
export interface LeagueEntryDTO {
leagueId: string
queueType: string
tier: string
rank: string
summonerId: string
summonerName: string
leaguePoints: number
wins: number
losses: number
veteran: boolean
inactive: boolean
freshBlood: boolean
hotStreak: boolean
miniSeries?: MiniSeriesDTO
}
interface MiniSeriesDTO {
losses: number
progress: string
target: number
wins: number
}
export default class LeagueEndpoint {
private config: JaxConfig
private limiter: RiotRateLimiter
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
this.config = config
this.limiter = limiter
}
public summonerID(summonerID: string, region: string): Promise<LeagueEntryDTO[]> {
return new JaxRequest(
region,
this.config,
`league/v4/entries/by-summoner/${summonerID}`,
this.limiter,
300
).execute()
}
}

View file

@ -0,0 +1,218 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import { getRiotRegion } from 'App/helpers'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
export interface MatchDto {
metadata: MetadataDto
info: InfoDto
}
export interface MetadataDto {
dataVersion: string
matchId: string
participants: string[]
}
export interface InfoDto {
gameCreation: number
gameDuration: number
gameId: number
gameMode: string
gameName: string
gameStartTimestamp: number
gameType: string
gameVersion: string
mapId: number
participants: ParticipantDto[]
platformId: string
queueId: number
teams: TeamDto[]
tournamentCode?: string
}
export interface ParticipantDto {
assists: number
baronKills: number
bountyLevel: number
champExperience: number
champLevel: number
championId: number
championName: string
championTransform: ChampionTransformDto
consumablesPurchased: number
damageDealtToObjectives: number
damageDealtToTurrets: number
damageSelfMitigated: number
deaths: number
detectorWardsPlaced: number
doubleKills: number
dragonKills: number
firstBloodAssist: boolean
firstBloodKill: boolean
firstTowerAssist: boolean
firstTowerKill: boolean
gameEndedInEarlySurrender: boolean
gameEndedInSurrender: boolean
goldEarned: number
goldSpent: number
individualPosition: 'Invalid' | TeamPositionDto // TODO
inhibitorKills: number
item0: number
item1: number
item2: number
item3: number
item4: number
item5: number
item6: number
itemsPurchased: number
killingSprees: number
kills: number
lane: LaneDto // TODO
largestCriticalStrike: number
largestKillingSpree: number
largestMultiKill: number
longestTimeSpentLiving: number
magicDamageDealt: number
magicDamageDealtToChampions: number
magicDamageTaken: number
neutralMinionsKilled: number
nexusKills: number
objectivesStolen: number
objectivesStolenAssists: number
participantId: number
pentaKills: number
perks: PerksDto
physicalDamageDealt: number
physicalDamageDealtToChampions: number
physicalDamageTaken: number
profileIcon: number
puuid: string
quadraKills: number
riotIdName: string
riotIdTagline: string
role: RoleDto // TODO
sightWardsBoughtInGame: number
spell1Casts: number
spell2Casts: number
spell3Casts: number
spell4Casts: number
summoner1Casts: number
summoner1Id: number
summoner2Casts: number
summoner2Id: number
summonerId: string
summonerLevel: number
summonerName: string
teamEarlySurrendered: boolean
teamId: number
teamPosition: TeamPositionDto // TODO
timeCCingOthers: number
timePlayed: number
totalDamageDealt: number
totalDamageDealtToChampions: number
totalDamageShieldedOnTeammates: number
totalDamageTaken: number
totalHeal: number
totalHealsOnTeammates: number
totalMinionsKilled: number
totalTimeCCDealt: number
totalTimeSpentDead: number
totalUnitsHealed: number
tripleKills: number
trueDamageDealt: number
trueDamageDealtToChampions: number
trueDamageTaken: number
turretKills: number
unrealKills: number
visionScore: number
visionWardsBoughtInGame: number
wardsKilled: number
wardsPlaced: number
win: boolean
}
export enum ChampionTransformDto {
None,
Slayer,
Assasin,
}
export type LaneDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM'
export interface PerksDto {
statPerks: PerkStatsDto
styles: PerkStyleDto[]
}
export interface PerkStatsDto {
defense: number
flex: number
offense: number
}
export interface PerkStyleDto {
description: 'primaryStyle' | 'subStyle'
selections: PerkStyleSelectionDto[]
style: number
}
export interface PerkStyleSelectionDto {
perk: number
var1: number
var2: number
var3: number
}
export type RoleDto = 'NONE' | 'DUO' | 'SOLO' | 'CARRY' | 'SUPPORT'
export type TeamPositionDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM' | 'UTILITY'
export interface TeamDto {
bans: BanDto[]
objectives: ObjectivesDto
teamId: number
win: boolean
}
export interface BanDto {
championId: number
pickTurn: number
}
export interface ObjectivesDto {
baron: ObjectiveDto
champion: ObjectiveDto
dragon: ObjectiveDto
inhibitor: ObjectiveDto
riftHerald: ObjectiveDto
tower: ObjectiveDto
}
export interface ObjectiveDto {
first: boolean
kills: number
}
export default class MatchEndpoint {
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: string, region: string): Promise<MatchDto> {
return new JaxRequest(
getRiotRegion(region),
this.config,
`match/v5/matches/${matchID}`,
this.limiter,
1500
).execute()
}
}

View file

@ -0,0 +1,54 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import { getRiotRegion } from 'App/helpers'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
// export interface MatchlistDto {
// startIndex: number,
// totalGames: number,
// endIndex: number,
// matches: MatchReferenceDto[]
// }
// export interface MatchReferenceDto {
// gameId: number,
// role: string,
// season: number,
// platformId: string,
// champion: number,
// queue: number,
// lane: string,
// timestamp: number,
// seasonMatch?: number
// }
/**
*
* ===============================================
* V5
* ===============================================
*
*/
export type MatchlistDto = string[]
export default class MatchlistEndpoint {
private config: JaxConfig
private limiter: RiotRateLimiter
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
this.config = config
this.limiter = limiter
}
public puuid(puuid: string, region: string, beginIndex = 0, count = 100): Promise<MatchlistDto> {
return new JaxRequest(
getRiotRegion(region),
this.config,
`match/v5/matches/by-puuid/${puuid}/ids?start=${beginIndex}&count=${count}`,
this.limiter,
0
).execute()
}
}

View file

@ -0,0 +1,78 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import RiotRateLimiter from 'riot-ratelimiter'
import { LeagueEntriesByQueue } from 'App/Services/SummonerService'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
export interface CurrentGameInfo {
gameId: number
gameType: string
gameStartTime: number
mapId: number
gameLength: number
platformId: string
gameMode: string
bannedChampions: BannedChampion[]
gameQueueConfigId: number
observers: Observer
participants: CurrentGameParticipant[]
}
export interface BannedChampion {
pickTurn: number
championId: number
teamId: number
}
export interface Observer {
encryptionKey: string
}
export interface CurrentGameParticipant {
championId: number
perks: Perks
profileIconId: number
bot: boolean
teamId: number
summonerName: string
summonerId: string
spell1Id: number
spell2Id: number
gameCustomizationObjects: GameCustomizationObject[]
// Custom types from here
role?: string
runes?: { primaryRune: string; secondaryRune: string } | {}
level?: number
rank?: LeagueEntriesByQueue
}
export interface Perks {
perkIds: number[]
perkStyle: number
perkSubStyle: number
}
export interface GameCustomizationObject {
category: string
content: string
}
export default class SpectatorEndpoint {
private config: JaxConfig
private limiter: RiotRateLimiter
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
this.config = config
this.limiter = limiter
}
public summonerID(summonerID: string, region: string) {
return new JaxRequest(
region,
this.config,
`spectator/v4/active-games/by-summoner/${summonerID}`,
this.limiter,
0
).execute()
}
}

View file

@ -0,0 +1,45 @@
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import RiotRateLimiter from 'riot-ratelimiter'
import { JaxConfig } from '../../JaxConfig'
import JaxRequest from '../JaxRequest'
export interface SummonerDTO {
accountId: string
profileIconId: number
revisionDate: number
name: string
id: string
puuid: string
summonerLevel: number
region?: string
}
export default class SummonerEndpoint {
private config: JaxConfig
private limiter: RiotRateLimiter
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
this.config = config
this.limiter = limiter
}
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()
}
}

View file

@ -0,0 +1,42 @@
import LeagueEndpoint from './Endpoints/LeagueEndpoint'
import MatchEndpoint from './Endpoints/MatchEndpoint'
import MatchlistEndpoint from './Endpoints/MatchlistEndpoint'
import SummonerEndpoint from './Endpoints/SummonerEndpoint'
import SpectatorEndpoint from './Endpoints/SpectatorEndpoint'
import CDragonEndpoint from './Endpoints/CDragonEndpoint'
import { JaxConfig } from '../JaxConfig'
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
import RiotRateLimiter from 'riot-ratelimiter'
import { STRATEGY } from 'riot-ratelimiter/dist/RateLimiter'
export default class Jax {
public key: string
public limiter: RiotRateLimiter
public config: JaxConfig
public League: LeagueEndpoint
public Match: MatchEndpoint
public Matchlist: MatchlistEndpoint
public Spectator: SpectatorEndpoint
public Summoner: SummonerEndpoint
public CDragon: CDragonEndpoint
constructor(config: JaxConfig) {
this.key = config.key
// this.limiter = new RiotRateLimiter({
// debug: true,
// retryCount: 0,
// })
this.limiter = new RiotRateLimiter({
debug: false,
strategy: STRATEGY.SPREAD,
})
this.config = config
this.League = new LeagueEndpoint(this.config, this.limiter)
this.Match = new MatchEndpoint(this.config, this.limiter)
this.Matchlist = new MatchlistEndpoint(this.config, this.limiter)
this.Spectator = new SpectatorEndpoint(this.config, this.limiter)
this.Summoner = new SummonerEndpoint(this.config, this.limiter)
this.CDragon = new CDragonEndpoint(this.config)
}
}

View file

@ -0,0 +1,84 @@
import { promisify } from 'util'
import { JaxConfig } from '../JaxConfig'
import Logger from '@ioc:Adonis/Core/Logger'
import Redis from '@ioc:Adonis/Addons/Redis'
import RiotRateLimiter from 'riot-ratelimiter'
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
export default class JaxRequest {
private region: string
private config: JaxConfig
private endpoint: string
private limiter: RiotRateLimiter
private cacheTime: number
private retries: number
private sleep: { (ms: number): Promise<void>; <T>(ms: number, value: T): Promise<T> }
constructor(
region: string,
config: JaxConfig,
endpoint: string,
limiter: RiotRateLimiter,
cacheTime: number
) {
this.region = region
this.config = config
this.endpoint = endpoint
this.limiter = limiter
this.cacheTime = cacheTime
this.retries = config.requestOptions.retriesBeforeAbort
this.sleep = promisify(setTimeout)
}
public async execute() {
const url = `https://${this.region}.api.riotgames.com/lol/${this.endpoint}`
// Redis cache
if (this.cacheTime > 0) {
const requestCached = await Redis.get(url)
if (requestCached) {
return JSON.parse(requestCached)
}
}
try {
const resp: any = await this.limiter.executing({
url,
token: this.config.key,
resolveWithFullResponse: false,
})
if (this.cacheTime > 0) {
await Redis.setex(url, this.cacheTime, resp)
}
return JSON.parse(resp)
} catch ({ statusCode, ...rest }) {
this.retries--
if (statusCode !== 500 && statusCode !== 503 && statusCode !== 504) {
//
// Don't log 404 when summoner isn't playing or the summoner doesn't exist
// Or if summoner has no MatchList
if (
!this.endpoint.includes('spectator/v4/active-games/by-summoner') &&
!this.endpoint.includes('summoner/v4/summoners/by-name') &&
!this.endpoint.includes('match/v4/matchlists/by-account')
) {
Logger.error(`JaxRequest Error ${statusCode}: `, rest)
}
return
}
console.log('====================================')
console.log(statusCode)
console.log('====================================')
if (this.retries > 0) {
await this.sleep(this.config.requestOptions.delayBeforeRetry)
return this.execute()
}
}
}
}

View file

@ -0,0 +1,91 @@
import Jax from './Jax'
import { SummonerDTO } from 'App/Services/Jax/src/Endpoints/SummonerEndpoint'
import { LeagueEntryDTO } from './Jax/src/Endpoints/LeagueEndpoint'
import Summoner from 'App/Models/Summoner'
export interface LeagueEntriesByQueue {
soloQ?: LeagueEntryByQueue
flex5v5?: LeagueEntryByQueue
}
export interface LeagueEntryByQueue extends LeagueEntryDTO {
fullRank: string
winrate: string
shortName: string | number
}
class SummonerService {
private uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
private leaguesNumbers = { I: 1, II: 2, III: 3, IV: 4 }
/**
* Helper to transform League Data from the Riot API
* @param league raw data of the league from Riot API
*/
private getleagueData(league?: LeagueEntryDTO): LeagueEntryByQueue | null {
if (!league) {
return null
}
const fullRank = this.uniqueLeagues.includes(league.tier)
? league.tier
: `${league.tier} ${league.rank}`
const winrate = +((league.wins * 100) / (league.wins + league.losses)).toFixed(1) + '%'
const shortName = this.uniqueLeagues.includes(league.tier)
? league.leaguePoints
: league.tier[0] + this.leaguesNumbers[league.rank]
return {
...league,
fullRank,
winrate,
shortName,
}
}
/**
* Get account infos for a searched summoner name
* @param summonerName
* @param region
*/
public async getAccount(summonerName: string, region: string) {
const name = summonerName.toLowerCase()
const account = await Jax.Summoner.summonerName(name, region)
return account
}
/**
* Return the full list of old and actual summoner names
* @param account of the summoner
* @param summonerDB summoner in the database
*/
public async getAllSummonerNames(account: SummonerDTO, summonerDB: Summoner) {
if (!summonerDB.names.find((n) => n.name === account.name)) {
await summonerDB.related('names').create({
name: account.name,
})
}
return summonerDB.names
}
/**
* Get ranked data for a specific Summoner
* @param account
* @param region
*/
public async getRanked(account: SummonerDTO, region: string): Promise<LeagueEntriesByQueue> {
const ranked = await Jax.League.summonerID(account.id, region)
const result: LeagueEntriesByQueue = {}
if (ranked && ranked.length) {
result.soloQ =
this.getleagueData(ranked.find((e) => e.queueType === 'RANKED_SOLO_5x5')) || undefined
result.flex5v5 =
this.getleagueData(ranked.find((e) => e.queueType === 'RANKED_FLEX_SR')) || undefined
}
return result
}
}
export default new SummonerService()

110
server-v2/app/helpers.ts Normal file
View file

@ -0,0 +1,110 @@
import MatchPlayer from './Models/MatchPlayer'
/**
* All League of Legends regions used in Riot API
*/
export enum LeagueRegion {
BRAZIL = 'br1',
EUROPE_NORTHEAST = 'eun1',
EUROPE_WEST = 'euw1',
KOREA = 'kr',
LATIN_AMERICA_NORTH = 'la1',
LATIN_AMERICA_SOUTH = 'la2',
NORTH_AMERICA = 'na1',
OCEANIA = 'oc1',
RUSSIA = 'ru',
TURKEY = 'tr1',
JAPAN = 'jp1',
}
/**
* New regions used in Riot API >= v5
*/
export enum RiotRegion {
AMERICAS = 'americas',
ASIA = 'asia',
EUROPE = 'europe',
}
/**
* Map old Riot API regions to new ones
* @param region : old region
* @returns new region name
*/
export function getRiotRegion(region: string): RiotRegion {
switch (
region as LeagueRegion // TODO: remove cast when region is typed to "Region" everywhere instead of string
) {
case LeagueRegion.NORTH_AMERICA:
case LeagueRegion.BRAZIL:
case LeagueRegion.LATIN_AMERICA_NORTH:
case LeagueRegion.LATIN_AMERICA_SOUTH:
case LeagueRegion.OCEANIA:
return RiotRegion.AMERICAS
case LeagueRegion.KOREA:
case LeagueRegion.JAPAN:
return RiotRegion.ASIA
case LeagueRegion.EUROPE_NORTHEAST:
case LeagueRegion.EUROPE_WEST:
case LeagueRegion.TURKEY:
case LeagueRegion.RUSSIA:
return RiotRegion.EUROPE
}
}
/**
* League of Legends queues with defined role for each summoner
*/
export const queuesWithRole = [
0, // Custom
400, // Draft
420, // Solo/Duo
430, // Blind,
440, // Flex
700, // Clash
]
/**
* League of Legends seasons timestamps
*/
export const seasons = {
0: 9,
1578628800000: 10,
1604970061000: 10.5, // Preseason 11
1610078400000: 11,
}
/**
* League of Legends all support item ids
*/
export const supportItems = [3850, 3851, 3853, 3854, 3855, 3857, 3858, 3859, 3860, 3862, 3863, 3864]
/**
* Get season number for a match
* @param timestamp
*/
export function getSeasonNumber(timestamp: number): number {
const arrSeasons = Object.keys(seasons).map((k) => Number(k))
arrSeasons.push(timestamp)
arrSeasons.sort()
const indexSeason = arrSeasons.indexOf(timestamp) - 1
return seasons[arrSeasons[indexSeason]]
}
/**
* Return current League of Legends season number
*/
export function getCurrentSeason(): number {
const lastTimestamp = Object.keys(seasons).pop()!
return seasons[lastTimestamp]
}
/**
* Sort array of Players by roles according to a specific order
* @param a first player
* @param b second player
*/
export function sortTeamByRole(a: MatchPlayer, b: MatchPlayer) {
const sortingArr = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'SUPPORT']
return sortingArr.indexOf(a.teamPosition) - sortingArr.indexOf(b.teamPosition)
}

File diff suppressed because it is too large Load diff

View file

@ -27,10 +27,13 @@
"@adonisjs/lucid": "^16.0.2",
"@adonisjs/redis": "^7.0.9",
"@adonisjs/repl": "^3.1.6",
"got": "^11.8.2",
"luxon": "^2.0.2",
"pg": "^8.7.1",
"proxy-addr": "^2.0.7",
"reflect-metadata": "^0.1.13",
"request": "^2.88.2",
"riot-ratelimiter": "^0.1.5",
"source-map-support": "^0.5.20"
}
}