mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: add Jax Service back
This commit is contained in:
parent
753bda3418
commit
63b42f7c86
15 changed files with 2535 additions and 21 deletions
21
server-v2/app/Services/Jax/JaxConfig.ts
Normal file
21
server-v2/app/Services/Jax/JaxConfig.ts
Normal 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,
|
||||
},
|
||||
}
|
||||
4
server-v2/app/Services/Jax/index.ts
Normal file
4
server-v2/app/Services/Jax/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import Jax from './src/Jax'
|
||||
import { JAX_CONFIG } from './JaxConfig'
|
||||
|
||||
export = new Jax(JAX_CONFIG)
|
||||
53
server-v2/app/Services/Jax/src/CDragonRequest.ts
Normal file
53
server-v2/app/Services/Jax/src/CDragonRequest.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
server-v2/app/Services/Jax/src/Endpoints/CDragonEndpoint.ts
Normal file
104
server-v2/app/Services/Jax/src/Endpoints/CDragonEndpoint.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
48
server-v2/app/Services/Jax/src/Endpoints/LeagueEndpoint.ts
Normal file
48
server-v2/app/Services/Jax/src/Endpoints/LeagueEndpoint.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
218
server-v2/app/Services/Jax/src/Endpoints/MatchEndpoint.ts
Normal file
218
server-v2/app/Services/Jax/src/Endpoints/MatchEndpoint.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
45
server-v2/app/Services/Jax/src/Endpoints/SummonerEndpoint.ts
Normal file
45
server-v2/app/Services/Jax/src/Endpoints/SummonerEndpoint.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
42
server-v2/app/Services/Jax/src/Jax.ts
Normal file
42
server-v2/app/Services/Jax/src/Jax.ts
Normal 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)
|
||||
}
|
||||
}
|
||||
84
server-v2/app/Services/Jax/src/JaxRequest.ts
Normal file
84
server-v2/app/Services/Jax/src/JaxRequest.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
server-v2/app/Services/SummonerService.ts
Normal file
91
server-v2/app/Services/SummonerService.ts
Normal 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
110
server-v2/app/helpers.ts
Normal 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)
|
||||
}
|
||||
1601
server-v2/package-lock.json
generated
1601
server-v2/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue