mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: more work on summoner/basic endpoint
This commit is contained in:
parent
58b26d5838
commit
e35492840e
8 changed files with 252 additions and 38 deletions
|
|
@ -1,16 +1,20 @@
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||||
|
import { SummonerModel } from '@ioc:Adonis/League'
|
||||||
import mongodb from '@ioc:Mongodb/Database'
|
import mongodb from '@ioc:Mongodb/Database'
|
||||||
|
import MatchRepository from 'App/Repositories/MatchRepository'
|
||||||
import Jax from 'App/Services/Jax'
|
import Jax from 'App/Services/Jax'
|
||||||
|
import MatchService from 'App/Services/MatchService'
|
||||||
import SummonerService from 'App/Services/SummonerService'
|
import SummonerService from 'App/Services/SummonerService'
|
||||||
|
|
||||||
export default class SummonersController {
|
export default class SummonersController {
|
||||||
// private async getSeasons (puuid) {
|
private async getSeasons (puuid: string) {
|
||||||
// let seasons = await MatchRepository.seasons(puuid)
|
let seasons = await MatchRepository.seasons(puuid)
|
||||||
// return seasons.length ? seasons.map(s => s._id) : [10]
|
return seasons.length ? seasons.map(s => s._id) : [10]
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST: get basic summoner data
|
* POST: get basic summoner data
|
||||||
|
* @param ctx
|
||||||
*/
|
*/
|
||||||
public async basic ({ request, response }: HttpContextContract) {
|
public async basic ({ request, response }: HttpContextContract) {
|
||||||
console.time('all')
|
console.time('all')
|
||||||
|
|
@ -41,9 +45,10 @@ export default class SummonersController {
|
||||||
// )
|
// )
|
||||||
|
|
||||||
const summonersCollection = await mongodb.connection().collection('summoners')
|
const summonersCollection = await mongodb.connection().collection('summoners')
|
||||||
const summonerDB = await summonersCollection.findOne({ puuid: account.puuid })
|
let summonerDB:SummonerModel|null = await summonersCollection.findOne({ puuid: account.puuid })
|
||||||
if(!summonerDB) {
|
if(!summonerDB) {
|
||||||
await summonersCollection.insertOne({ puuid: account.puuid })
|
await summonersCollection.insertOne({ puuid: account.puuid })
|
||||||
|
summonerDB = {puuid: account.puuid }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summoner names
|
// Summoner names
|
||||||
|
|
|
||||||
43
server-new/app/Repositories/MatchRepository.ts
Normal file
43
server-new/app/Repositories/MatchRepository.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import mongodb from '@ioc:Mongodb/Database'
|
||||||
|
|
||||||
|
class MatchRepository {
|
||||||
|
private season?: number
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
// TODO: keep matches collection in the repo instance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic matchParams used in a lot of requests
|
||||||
|
* @param puuid of the summoner
|
||||||
|
*/
|
||||||
|
private _matchParams (puuid: string) {
|
||||||
|
return {
|
||||||
|
summoner_puuid: puuid,
|
||||||
|
result: { $not: { $eq: 'Remake' } },
|
||||||
|
gamemode: { $nin: [800, 810, 820, 830, 840, 850] },
|
||||||
|
season: this.season ? this.season : { $exists: true },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Summoner's played seasons
|
||||||
|
* @param puuid of the summoner
|
||||||
|
*/
|
||||||
|
public async seasons (puuid: string) {
|
||||||
|
this.season = undefined
|
||||||
|
const matchesCollections = await mongodb.connection().collection('matches')
|
||||||
|
|
||||||
|
return matchesCollections.aggregate([
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
...this._matchParams(puuid),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$group: { _id: '$season' },
|
||||||
|
},
|
||||||
|
]).toArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new MatchRepository()
|
||||||
|
|
@ -2,6 +2,25 @@ import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
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
|
||||||
|
}
|
||||||
|
|
||||||
export default class MatchlistEndpoint {
|
export default class MatchlistEndpoint {
|
||||||
private config: JaxConfig
|
private config: JaxConfig
|
||||||
private limiter: RiotRateLimiter
|
private limiter: RiotRateLimiter
|
||||||
|
|
@ -11,7 +30,7 @@ export default class MatchlistEndpoint {
|
||||||
this.limiter = limiter
|
this.limiter = limiter
|
||||||
}
|
}
|
||||||
|
|
||||||
public accountID (accountID: number, region: string, beginIndex = 0) {
|
public accountID (accountID: string, region: string, beginIndex = 0): Promise<MatchlistDto> {
|
||||||
return new JaxRequest(
|
return new JaxRequest(
|
||||||
region,
|
region,
|
||||||
this.config,
|
this.config,
|
||||||
|
|
|
||||||
136
server-new/app/Services/MatchService.ts
Normal file
136
server-new/app/Services/MatchService.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
import Jax from './Jax'
|
||||||
|
// import Logger from '@ioc:Adonis/Core/Logger'
|
||||||
|
import { getSeasonNumber } from 'App/helpers'
|
||||||
|
import { MatchReferenceDto } from './Jax/src/Endpoints/MatchListEndpoint'
|
||||||
|
import { SummonerDTO } from './Jax/src/Endpoints/SummonerEndpoint'
|
||||||
|
import { SummonerModel } from '@ioc:Adonis/League'
|
||||||
|
|
||||||
|
class MatchService {
|
||||||
|
/**
|
||||||
|
* Add 100 matches at a time to MatchList until the stopFetching condition is true
|
||||||
|
* @param account of the summoner
|
||||||
|
* @param stopFetching condition to stop fetching the MatchList
|
||||||
|
*/
|
||||||
|
private async _fetchMatchListUntil (account: SummonerDTO, stopFetching: any) {
|
||||||
|
let matchList: MatchReferenceDto[] = []
|
||||||
|
let alreadyIn = false
|
||||||
|
let index = 0
|
||||||
|
do {
|
||||||
|
let { matches: newMatchList } = await Jax.Matchlist.accountID(account.accountId, account.region as string, index)
|
||||||
|
// Error while fetching Riot API
|
||||||
|
if (!newMatchList) {
|
||||||
|
matchList = matchList.map(m => {
|
||||||
|
m.seasonMatch = getSeasonNumber(m.timestamp)
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
return matchList
|
||||||
|
}
|
||||||
|
matchList = [...matchList, ...newMatchList]
|
||||||
|
alreadyIn = newMatchList.length === 0 || stopFetching(newMatchList)
|
||||||
|
// If the match is made in another region : we stop fetching
|
||||||
|
if (matchList[matchList.length - 1].platformId.toLowerCase() !== account.region) {
|
||||||
|
alreadyIn = true
|
||||||
|
}
|
||||||
|
index += 100
|
||||||
|
} while (!alreadyIn)
|
||||||
|
|
||||||
|
// Remove matches from MatchList made in another region and tutorial games
|
||||||
|
const tutorialModes = [2000, 2010, 2020]
|
||||||
|
matchList = matchList
|
||||||
|
.filter(m => {
|
||||||
|
const sameRegion = m.platformId.toLowerCase() === account.region
|
||||||
|
const notATutorialGame = !tutorialModes.includes(m.queue)
|
||||||
|
|
||||||
|
return sameRegion && notATutorialGame
|
||||||
|
})
|
||||||
|
.map(m => {
|
||||||
|
m.seasonMatch = getSeasonNumber(m.timestamp)
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
|
||||||
|
return matchList
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Update the full MatchList of the summoner (min. 4 months)
|
||||||
|
* @param account of the summoner
|
||||||
|
* @param summonerDB summoner in the database
|
||||||
|
*/
|
||||||
|
public async updateMatchList (account: SummonerDTO, summonerDB: SummonerModel) {
|
||||||
|
console.time('matchList')
|
||||||
|
|
||||||
|
// Summoner has already been searched : we already have a MatchList and we need to update it
|
||||||
|
if (summonerDB.matchList) {
|
||||||
|
// Get MatchList
|
||||||
|
const matchList = await this._fetchMatchListUntil(account, (newMatchList: MatchReferenceDto[]) => {
|
||||||
|
return summonerDB.matchList!.some(m => m.gameId === newMatchList[newMatchList.length - 1].gameId)
|
||||||
|
})
|
||||||
|
// Update Summoner's MatchList
|
||||||
|
for (const match of matchList.reverse()) {
|
||||||
|
if (!summonerDB.matchList.some(m => m.gameId === match.gameId)) {
|
||||||
|
summonerDB.matchList.unshift(match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // First search of the Summoner
|
||||||
|
const today = Date.now()
|
||||||
|
// Get MatchList
|
||||||
|
const matchList = await this._fetchMatchListUntil(account, (newMatchList: MatchReferenceDto[]) => {
|
||||||
|
return (newMatchList.length !== 100 || today - newMatchList[newMatchList.length - 1].timestamp > 10368000000)
|
||||||
|
})
|
||||||
|
// Create Summoner's MatchList in Database
|
||||||
|
summonerDB.matchList = matchList
|
||||||
|
}
|
||||||
|
console.timeEnd('matchList')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch list of matches for a specific Summoner
|
||||||
|
* @param account of the summoner
|
||||||
|
* @param gameIds of the matches to fetch
|
||||||
|
* @param summonerDB summoner in the database
|
||||||
|
*/
|
||||||
|
// public async getMatches (account, gameIds, summonerDB) {
|
||||||
|
// console.time('getMatches')
|
||||||
|
|
||||||
|
// let matchesDetails = []
|
||||||
|
// const matchesToGetFromRiot = []
|
||||||
|
// for (let i = 0; i < gameIds.length; ++i) {
|
||||||
|
// const matchSaved = await summonerDB.matches().where({ gameId: gameIds[i] }).first()
|
||||||
|
// if (matchSaved) {
|
||||||
|
// matchesDetails.push(matchSaved)
|
||||||
|
// } else {
|
||||||
|
// matchesToGetFromRiot.push(gameIds[i])
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const requests = matchesToGetFromRiot.map(gameId => Jax.Match.get(gameId, account.region))
|
||||||
|
// let matchesFromApi = await Promise.all(requests)
|
||||||
|
|
||||||
|
// /* If we have to store some matches in the db */
|
||||||
|
// if (matchesFromApi.length !== 0) {
|
||||||
|
// // Try to see why matches are sometimes undefined
|
||||||
|
// matchesFromApi.filter(m => {
|
||||||
|
// if (m === undefined) {
|
||||||
|
// Logger.info(`Match undefined, summoner: ${summonerDB.puuid}`, m)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// // Transform raw matches data
|
||||||
|
// await BasicMatchTransformer.transform(matchesFromApi, { account })
|
||||||
|
|
||||||
|
// /* Save all matches from Riot Api in db */
|
||||||
|
// for (const match of matchesFromApi) {
|
||||||
|
// await summonerDB.matches().create(match)
|
||||||
|
// match.newMatch = true
|
||||||
|
// }
|
||||||
|
// matchesDetails = [...matchesDetails, ...matchesFromApi]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* Sort matches */
|
||||||
|
// matchesDetails.sort((a, b) => (a.date < b.date) ? 1 : -1)
|
||||||
|
// console.timeEnd('getMatches')
|
||||||
|
|
||||||
|
// return matchesDetails
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new MatchService()
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
import Jax from './Jax'
|
import Jax from './Jax'
|
||||||
import { SummonerDTO } from 'App/Services/Jax/src/Endpoints/SummonerEndpoint'
|
import { SummonerDTO } from 'App/Services/Jax/src/Endpoints/SummonerEndpoint'
|
||||||
import { LeagueEntryDTO } from './Jax/src/Endpoints/LeagueEndpoint'
|
import { LeagueEntryDTO } from './Jax/src/Endpoints/LeagueEndpoint'
|
||||||
|
import { SummonerModel } from '@ioc:Adonis/League'
|
||||||
|
|
||||||
class SummonerService {
|
class SummonerService {
|
||||||
private uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
|
private uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
|
||||||
|
|
@ -46,10 +45,10 @@ class SummonerService {
|
||||||
* @param account of the summoner
|
* @param account of the summoner
|
||||||
* @param summonerDB summoner in the database
|
* @param summonerDB summoner in the database
|
||||||
*/
|
*/
|
||||||
public getAllSummonerNames (account: SummonerDTO, summonerDB:any) {
|
public getAllSummonerNames (account: SummonerDTO, summonerDB:SummonerModel) {
|
||||||
const names = summonerDB.names ? summonerDB.names : []
|
const names = summonerDB.names ? summonerDB.names : []
|
||||||
|
|
||||||
if (!names.find((n: any) => n.name === account.name)) {
|
if (!names.find(n => n.name === account.name)) {
|
||||||
names.push({
|
names.push({
|
||||||
name: account.name,
|
name: account.name,
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* League of Legends queues with defined role for each summoner
|
* League of Legends queues with defined role for each summoner
|
||||||
*/
|
*/
|
||||||
const queuesWithRole = [
|
export const queuesWithRole = [
|
||||||
0, // Custom
|
0, // Custom
|
||||||
400, // Draft
|
400, // Draft
|
||||||
420, // Solo/Duo
|
420, // Solo/Duo
|
||||||
|
|
@ -13,7 +13,7 @@ const queuesWithRole = [
|
||||||
/**
|
/**
|
||||||
* League of Legends seasons timestamps
|
* League of Legends seasons timestamps
|
||||||
*/
|
*/
|
||||||
const seasons = {
|
export const seasons = {
|
||||||
0: 9,
|
0: 9,
|
||||||
1578628800000: 10,
|
1578628800000: 10,
|
||||||
}
|
}
|
||||||
|
|
@ -21,30 +21,26 @@ const seasons = {
|
||||||
/**
|
/**
|
||||||
* League of Legends all support item ids
|
* League of Legends all support item ids
|
||||||
*/
|
*/
|
||||||
const supportItems = [3850, 3851, 3853, 3854, 3855, 3857, 3858, 3859, 3860, 3862, 3863, 3864]
|
export const supportItems = [3850, 3851, 3853, 3854, 3855, 3857, 3858, 3859, 3860, 3862, 3863, 3864]
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
queuesWithRole,
|
* Get season number for a match
|
||||||
seasons,
|
* @param timestamp
|
||||||
supportItems,
|
*/
|
||||||
/**
|
export function getSeasonNumber (timestamp: number) {
|
||||||
* Get season number for a match
|
const arrSeasons = Object.keys(seasons).map(k => Number(k))
|
||||||
*/
|
arrSeasons.push(timestamp)
|
||||||
getSeasonNumber (timestamp: number) {
|
arrSeasons.sort()
|
||||||
const arrSeasons = Object.keys(seasons).map(k => Number(k))
|
const indexSeason = arrSeasons.indexOf(timestamp) - 1
|
||||||
arrSeasons.push(timestamp)
|
return seasons[arrSeasons[indexSeason]]
|
||||||
arrSeasons.sort()
|
}
|
||||||
const indexSeason = arrSeasons.indexOf(timestamp) - 1
|
|
||||||
return seasons[arrSeasons[indexSeason]]
|
/**
|
||||||
},
|
* Sort array of Roles according to a specific order
|
||||||
/**
|
* @param a first role
|
||||||
*
|
* @param b second role
|
||||||
* Sort array of Roles according to a specific order
|
*/
|
||||||
* @param a first role
|
export function sortTeamByRole (a:any, b:any) {
|
||||||
* @param b second role
|
const sortingArr = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'SUPPORT']
|
||||||
*/
|
return sortingArr.indexOf(a.role) - sortingArr.indexOf(b.role)
|
||||||
sortTeamByRole (a:any, b:any) {
|
|
||||||
const sortingArr = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'SUPPORT']
|
|
||||||
return sortingArr.indexOf(a.role) - sortingArr.indexOf(b.role)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
declare module '@ioc:Adonis/League' {
|
declare module '@ioc:Adonis/League' {
|
||||||
interface Account {
|
import { MatchReferenceDto } from 'App/Services/Jax/src/Endpoints/MatchlistEndpoint'
|
||||||
|
|
||||||
|
interface SummonerModel {
|
||||||
|
puuid: string,
|
||||||
|
matchList?: MatchReferenceDto[],
|
||||||
|
names?: SummonerNames[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SummonerNames {
|
||||||
|
name: string,
|
||||||
|
date: Date
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,13 @@ Route.get('jax', async () => {
|
||||||
return { player: summoner }
|
return { player: summoner }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Route.get('test', async () => {
|
||||||
|
const summonersCollection = await mongodb.connection().collection('summoners')
|
||||||
|
const summonerDB = await summonersCollection.findOne({ puuid: 1234 })
|
||||||
|
|
||||||
|
return { player: summonerDB }
|
||||||
|
})
|
||||||
|
|
||||||
Route.post('/summoner/basic', 'SummonersController.basic')
|
Route.post('/summoner/basic', 'SummonersController.basic')
|
||||||
Route.post('/summoner/overview', 'SummonersController.overview')
|
Route.post('/summoner/overview', 'SummonersController.overview')
|
||||||
Route.post('/summoner/champions', 'SummonersController.champions')
|
Route.post('/summoner/champions', 'SummonersController.champions')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue