mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: delete old server folder + rename new one
This commit is contained in:
parent
5e33d0b0ba
commit
93f23a0d33
153 changed files with 4828 additions and 23836 deletions
|
|
@ -1,37 +0,0 @@
|
||||||
{
|
|
||||||
"typescript": true,
|
|
||||||
"commands": [
|
|
||||||
"./commands",
|
|
||||||
"@adonisjs/core/build/commands/index.js",
|
|
||||||
"@adonisjs/repl/build/commands",
|
|
||||||
"@adonisjs/lucid/build/commands"
|
|
||||||
],
|
|
||||||
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
|
||||||
"aliases": {
|
|
||||||
"App": "app",
|
|
||||||
"Config": "config",
|
|
||||||
"Database": "database",
|
|
||||||
"Contracts": "contracts"
|
|
||||||
},
|
|
||||||
"preloads": [
|
|
||||||
"./start/routes",
|
|
||||||
"./start/kernel",
|
|
||||||
{
|
|
||||||
"file": "./start/events",
|
|
||||||
"environment": [
|
|
||||||
"console",
|
|
||||||
"repl",
|
|
||||||
"web"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"providers": [
|
|
||||||
"./providers/AppProvider",
|
|
||||||
"@adonisjs/core",
|
|
||||||
"@adonisjs/lucid",
|
|
||||||
"@adonisjs/redis"
|
|
||||||
],
|
|
||||||
"aceProviders": [
|
|
||||||
"@adonisjs/repl"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.json]
|
|
||||||
insert_final_newline = ignore
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
PORT=3333
|
|
||||||
HOST=0.0.0.0
|
|
||||||
NODE_ENV=development
|
|
||||||
APP_KEY=
|
|
||||||
DRIVE_DISK=local
|
|
||||||
|
|
||||||
DB_CONNECTION=pg
|
|
||||||
PG_HOST=localhost
|
|
||||||
PG_PORT=5432
|
|
||||||
PG_USER=
|
|
||||||
PG_PASSWORD=
|
|
||||||
PG_DB_NAME=
|
|
||||||
|
|
||||||
REDIS_CONNECTION=local
|
|
||||||
REDIS_HOST=127.0.0.1
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
RIOT_API_KEY=
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
build
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"extends": ["plugin:adonis/typescriptApp", "prettier"],
|
|
||||||
"plugins": ["prettier"],
|
|
||||||
"rules": {
|
|
||||||
"prettier/prettier": ["error"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
server-v2/.gitignore
vendored
7
server-v2/.gitignore
vendored
|
|
@ -1,7 +0,0 @@
|
||||||
node_modules
|
|
||||||
build
|
|
||||||
coverage
|
|
||||||
.vscode
|
|
||||||
.DS_STORE
|
|
||||||
.env
|
|
||||||
tmp
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Ace Commands
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This file is the entry point for running ace commands.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
require('reflect-metadata')
|
|
||||||
require('source-map-support').install({ handleUncaughtExceptions: false })
|
|
||||||
|
|
||||||
const { Ignitor } = require('@adonisjs/core/build/standalone')
|
|
||||||
new Ignitor(__dirname)
|
|
||||||
.ace()
|
|
||||||
.handle(process.argv.slice(2))
|
|
||||||
|
|
@ -1,294 +0,0 @@
|
||||||
{
|
|
||||||
"commands": {
|
|
||||||
"load:v4": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true,
|
|
||||||
"stayAlive": false
|
|
||||||
},
|
|
||||||
"commandPath": "./commands/LoadV4Matches",
|
|
||||||
"commandName": "load:v4",
|
|
||||||
"description": "Load matches for a given Summoner from the old Match-V4 endpoint",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"propertyName": "summoner",
|
|
||||||
"name": "summoner",
|
|
||||||
"required": true,
|
|
||||||
"description": "Summoner name to seach"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"propertyName": "region",
|
|
||||||
"name": "region",
|
|
||||||
"required": true,
|
|
||||||
"description": "League region of the summoner"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": []
|
|
||||||
},
|
|
||||||
"dump:rcfile": {
|
|
||||||
"settings": {},
|
|
||||||
"commandPath": "@adonisjs/core/build/commands/DumpRc",
|
|
||||||
"commandName": "dump:rcfile",
|
|
||||||
"description": "Dump contents of .adonisrc.json file along with defaults",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": []
|
|
||||||
},
|
|
||||||
"list:routes": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/core/build/commands/ListRoutes",
|
|
||||||
"commandName": "list:routes",
|
|
||||||
"description": "List application routes",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "json",
|
|
||||||
"propertyName": "json",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Output as JSON"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"generate:key": {
|
|
||||||
"settings": {},
|
|
||||||
"commandPath": "@adonisjs/core/build/commands/GenerateKey",
|
|
||||||
"commandName": "generate:key",
|
|
||||||
"description": "Generate a new APP_KEY secret",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": []
|
|
||||||
},
|
|
||||||
"repl": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true,
|
|
||||||
"environment": "repl",
|
|
||||||
"stayAlive": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/repl/build/commands/AdonisRepl",
|
|
||||||
"commandName": "repl",
|
|
||||||
"description": "Start a new REPL session",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": []
|
|
||||||
},
|
|
||||||
"db:seed": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/DbSeed",
|
|
||||||
"commandName": "db:seed",
|
|
||||||
"description": "Execute database seeder files",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "connection",
|
|
||||||
"propertyName": "connection",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define a custom database connection for the seeders",
|
|
||||||
"alias": "c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "interactive",
|
|
||||||
"propertyName": "interactive",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Run seeders in interactive mode",
|
|
||||||
"alias": "i"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "files",
|
|
||||||
"propertyName": "files",
|
|
||||||
"type": "array",
|
|
||||||
"description": "Define a custom set of seeders files names to run",
|
|
||||||
"alias": "f"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"make:model": {
|
|
||||||
"settings": {},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/MakeModel",
|
|
||||||
"commandName": "make:model",
|
|
||||||
"description": "Make a new Lucid model",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"propertyName": "name",
|
|
||||||
"name": "name",
|
|
||||||
"required": true,
|
|
||||||
"description": "Name of the model class"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "migration",
|
|
||||||
"propertyName": "migration",
|
|
||||||
"type": "boolean",
|
|
||||||
"alias": "m",
|
|
||||||
"description": "Generate the migration for the model"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "controller",
|
|
||||||
"propertyName": "controller",
|
|
||||||
"type": "boolean",
|
|
||||||
"alias": "c",
|
|
||||||
"description": "Generate the controller for the model"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"make:migration": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/MakeMigration",
|
|
||||||
"commandName": "make:migration",
|
|
||||||
"description": "Make a new migration file",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"propertyName": "name",
|
|
||||||
"name": "name",
|
|
||||||
"required": true,
|
|
||||||
"description": "Name of the migration file"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "connection",
|
|
||||||
"propertyName": "connection",
|
|
||||||
"type": "string",
|
|
||||||
"description": "The connection flag is used to lookup the directory for the migration file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "folder",
|
|
||||||
"propertyName": "folder",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Pre-select a migration directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "create",
|
|
||||||
"propertyName": "create",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define the table name for creating a new table"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "table",
|
|
||||||
"propertyName": "table",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define the table name for altering an existing table"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"make:seeder": {
|
|
||||||
"settings": {},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/MakeSeeder",
|
|
||||||
"commandName": "make:seeder",
|
|
||||||
"description": "Make a new Seeder file",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"propertyName": "name",
|
|
||||||
"name": "name",
|
|
||||||
"required": true,
|
|
||||||
"description": "Name of the seeder class"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": []
|
|
||||||
},
|
|
||||||
"migration:run": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/Migration/Run",
|
|
||||||
"commandName": "migration:run",
|
|
||||||
"description": "Run pending migrations",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "connection",
|
|
||||||
"propertyName": "connection",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define a custom database connection",
|
|
||||||
"alias": "c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "force",
|
|
||||||
"propertyName": "force",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Explicitly force to run migrations in production"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dry-run",
|
|
||||||
"propertyName": "dryRun",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Print SQL queries, instead of running the migrations"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"migration:rollback": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/Migration/Rollback",
|
|
||||||
"commandName": "migration:rollback",
|
|
||||||
"description": "Rollback migrations to a given batch number",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "connection",
|
|
||||||
"propertyName": "connection",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define a custom database connection",
|
|
||||||
"alias": "c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "force",
|
|
||||||
"propertyName": "force",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Explictly force to run migrations in production"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dry-run",
|
|
||||||
"propertyName": "dryRun",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Print SQL queries, instead of running the migrations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "batch",
|
|
||||||
"propertyName": "batch",
|
|
||||||
"type": "number",
|
|
||||||
"description": "Define custom batch number for rollback. Use 0 to rollback to initial state"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"migration:status": {
|
|
||||||
"settings": {
|
|
||||||
"loadApp": true
|
|
||||||
},
|
|
||||||
"commandPath": "@adonisjs/lucid/build/commands/Migration/Status",
|
|
||||||
"commandName": "migration:status",
|
|
||||||
"description": "Check migrations current status.",
|
|
||||||
"args": [],
|
|
||||||
"aliases": [],
|
|
||||||
"flags": [
|
|
||||||
{
|
|
||||||
"name": "connection",
|
|
||||||
"propertyName": "connection",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Define a custom database connection",
|
|
||||||
"alias": "c"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"aliases": {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import Redis from '@ioc:Adonis/Addons/Redis'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
import RuneSerializer from 'App/Serializers/RuneSerializer'
|
|
||||||
import Jax from 'App/Services/Jax'
|
|
||||||
|
|
||||||
export default class CDragonController {
|
|
||||||
public async runes({ response }: HttpContextContract) {
|
|
||||||
const cacheUrl = 'cdragon-runes'
|
|
||||||
|
|
||||||
const requestCached = await Redis.get(cacheUrl)
|
|
||||||
if (requestCached) {
|
|
||||||
return response.json(requestCached)
|
|
||||||
}
|
|
||||||
|
|
||||||
const perks = await Jax.CDragon.perks()
|
|
||||||
const perkstyles = await Jax.CDragon.perkstyles()
|
|
||||||
|
|
||||||
const runesData = {
|
|
||||||
perks: RuneSerializer.serializePerks(perks),
|
|
||||||
perkstyles: RuneSerializer.serializeStyles(perkstyles.styles),
|
|
||||||
}
|
|
||||||
|
|
||||||
await Redis.set(cacheUrl, JSON.stringify(runesData), 'EX', 36000)
|
|
||||||
|
|
||||||
return response.json(runesData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
import Match from 'App/Models/Match'
|
|
||||||
import MatchPlayerRankParser from 'App/Parsers/MatchPlayerRankParser'
|
|
||||||
import DetailedMatchSerializer from 'App/Serializers/DetailedMatchSerializer'
|
|
||||||
import MatchPlayerRankSerializer from 'App/Serializers/MatchPlayerRankSerializer'
|
|
||||||
import MatchService from 'App/Services/MatchService'
|
|
||||||
import StatsService from 'App/Services/StatsService'
|
|
||||||
import DetailedMatchValidator from 'App/Validators/DetailedMatchValidator'
|
|
||||||
import MatchesIndexValidator from 'App/Validators/MatchesIndexValidator'
|
|
||||||
|
|
||||||
export default class MatchesController {
|
|
||||||
/**
|
|
||||||
* POST - Return data from matches searched by matchIds
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async index({ request, response }: HttpContextContract) {
|
|
||||||
const { puuid, region, matchIds, season } = await request.validate(MatchesIndexValidator)
|
|
||||||
const matches = await MatchService.getMatches(region, matchIds, puuid)
|
|
||||||
|
|
||||||
const stats = await StatsService.getSummonerStats(puuid, season)
|
|
||||||
return response.json({
|
|
||||||
matches,
|
|
||||||
stats,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST - Return details data for one specific match
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async show({ request, response }: HttpContextContract) {
|
|
||||||
console.time('MatchDetails')
|
|
||||||
const { matchId } = await request.validate(DetailedMatchValidator)
|
|
||||||
|
|
||||||
const match = await Match.query()
|
|
||||||
.where('id', matchId)
|
|
||||||
.preload('teams')
|
|
||||||
.preload('players', (playersQuery) => {
|
|
||||||
playersQuery.preload('ranks')
|
|
||||||
})
|
|
||||||
.firstOrFail()
|
|
||||||
|
|
||||||
const { match: matchDetails, ranksLoaded } = DetailedMatchSerializer.serializeOneMatch(match)
|
|
||||||
|
|
||||||
console.timeEnd('MatchDetails')
|
|
||||||
|
|
||||||
return response.json({
|
|
||||||
matchDetails,
|
|
||||||
ranksLoaded,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST - Return ranks of players for a specific game
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async showRanks({ request, response }: HttpContextContract) {
|
|
||||||
console.time('Ranks')
|
|
||||||
const { matchId } = await request.validate(DetailedMatchValidator)
|
|
||||||
const match = await Match.query().where('id', matchId).preload('players').firstOrFail()
|
|
||||||
const parsedRanks = await MatchPlayerRankParser.parse(match)
|
|
||||||
const serializedRanks = MatchPlayerRankSerializer.serialize(parsedRanks)
|
|
||||||
|
|
||||||
console.timeEnd('Ranks')
|
|
||||||
return response.json(serializedRanks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
import { getCurrentSeason } from 'App/helpers'
|
|
||||||
import Summoner from 'App/Models/Summoner'
|
|
||||||
import MatchRepository from 'App/Repositories/MatchRepository'
|
|
||||||
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
|
|
||||||
import LiveMatchSerializer from 'App/Serializers/LiveMatchSerializer'
|
|
||||||
import Jax from 'App/Services/Jax'
|
|
||||||
import MatchService from 'App/Services/MatchService'
|
|
||||||
import StatsService from 'App/Services/StatsService'
|
|
||||||
import SummonerService from 'App/Services/SummonerService'
|
|
||||||
import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator'
|
|
||||||
import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator'
|
|
||||||
import SummonerLiveValidator from 'App/Validators/SummonerLiveValidator'
|
|
||||||
import SummonerOverviewValidator from 'App/Validators/SummonerOverviewValidator'
|
|
||||||
import SummonerRecordValidator from 'App/Validators/SummonerRecordValidator'
|
|
||||||
|
|
||||||
export default class SummonersController {
|
|
||||||
public async basic({ request, response }: HttpContextContract) {
|
|
||||||
console.time('BASIC_REQUEST')
|
|
||||||
const { summoner, region } = await request.validate(SummonerBasicValidator)
|
|
||||||
const finalJSON: any = {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const account = await SummonerService.getAccount(summoner, region)
|
|
||||||
// Check if the summoner is found
|
|
||||||
if (!account) {
|
|
||||||
return response.json(null)
|
|
||||||
}
|
|
||||||
finalJSON.account = account
|
|
||||||
|
|
||||||
// Summoner in DB
|
|
||||||
const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid })
|
|
||||||
|
|
||||||
// Summoner names
|
|
||||||
finalJSON.account.names = await SummonerService.getAllSummonerNames(account, summonerDB)
|
|
||||||
|
|
||||||
// MATCH LIST
|
|
||||||
finalJSON.matchList = await MatchService.updateMatchList(account, region, summonerDB)
|
|
||||||
|
|
||||||
// All seasons the summoner has played
|
|
||||||
// TODO: check if there is a way to do that with V5...
|
|
||||||
finalJSON.seasons = [getCurrentSeason()]
|
|
||||||
|
|
||||||
// CURRENT GAME
|
|
||||||
const currentGame = await Jax.Spectator.summonerID(account.id, region)
|
|
||||||
finalJSON.playing = !!currentGame
|
|
||||||
finalJSON.current = currentGame
|
|
||||||
|
|
||||||
// RANKED STATS
|
|
||||||
finalJSON.ranked = await SummonerService.getRanked(account.id, region)
|
|
||||||
|
|
||||||
// RECENT ACTIVITY
|
|
||||||
finalJSON.recentActivity = await StatsService.getRecentActivity(account.puuid)
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
console.timeEnd('BASIC_REQUEST')
|
|
||||||
return response.json(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.timeEnd('BASIC_REQUEST')
|
|
||||||
return response.json(finalJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async overview({ request, response }: HttpContextContract) {
|
|
||||||
console.time('OVERVIEW_REQUEST')
|
|
||||||
const { puuid, region, season } = await request.validate(SummonerOverviewValidator)
|
|
||||||
const finalJSON: any = {}
|
|
||||||
|
|
||||||
// Summoner in DB
|
|
||||||
const summonerDB = await Summoner.firstOrCreate({ puuid: puuid })
|
|
||||||
|
|
||||||
// MATCHES BASIC
|
|
||||||
const matchlist = await summonerDB
|
|
||||||
.related('matchList')
|
|
||||||
.query()
|
|
||||||
.select('matchId')
|
|
||||||
.orderBy('matchId', 'desc')
|
|
||||||
.limit(10)
|
|
||||||
const matchIds = matchlist.map((m) => m.matchId)
|
|
||||||
|
|
||||||
finalJSON.matchesDetails = await MatchService.getMatches(region, matchIds, puuid)
|
|
||||||
|
|
||||||
console.time('STATS')
|
|
||||||
finalJSON.stats = await StatsService.getSummonerStats(puuid, season)
|
|
||||||
console.timeEnd('STATS')
|
|
||||||
|
|
||||||
console.timeEnd('OVERVIEW_REQUEST')
|
|
||||||
return response.json(finalJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST: get champions view summoner data
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async champions({ request, response }: HttpContextContract) {
|
|
||||||
console.time('championsRequest')
|
|
||||||
const { puuid, queue, season } = await request.validate(SummonerChampionValidator)
|
|
||||||
const championStats = await MatchRepository.championCompleteStats(puuid, queue, season)
|
|
||||||
const championStatsSerialized = championStats.map((champion) => {
|
|
||||||
return {
|
|
||||||
...champion,
|
|
||||||
champion: BasicMatchSerializer.getChampion(champion.id),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.timeEnd('championsRequest')
|
|
||||||
return response.json(championStatsSerialized)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST: get records view summoner data
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async records({ request, response }: HttpContextContract) {
|
|
||||||
console.time('recordsRequest')
|
|
||||||
const { puuid, season } = await request.validate(SummonerRecordValidator)
|
|
||||||
const records = await MatchRepository.records(puuid)
|
|
||||||
const recordsSerialized = records.map((record) => {
|
|
||||||
return {
|
|
||||||
...record,
|
|
||||||
what: record.what.split('.')[1],
|
|
||||||
champion: BasicMatchSerializer.getChampion(record.champion_id),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.timeEnd('recordsRequest')
|
|
||||||
return response.json(recordsSerialized)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST - Return live match detail
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async liveMatchDetails({ request, response }: HttpContextContract) {
|
|
||||||
console.time('liveMatchDetails')
|
|
||||||
const { id, region } = await request.validate(SummonerLiveValidator)
|
|
||||||
|
|
||||||
// CURRENT GAME
|
|
||||||
const currentGame = await Jax.Spectator.summonerID(id, region)
|
|
||||||
|
|
||||||
if (!currentGame) {
|
|
||||||
return response.json(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentGameSerialized = await LiveMatchSerializer.serializeOneMatch(currentGame, region)
|
|
||||||
console.timeEnd('liveMatchDetails')
|
|
||||||
|
|
||||||
return response.json(currentGameSerialized)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Http Exception Handler
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| AdonisJs will forward all exceptions occurred during an HTTP request to
|
|
||||||
| the following class. You can learn more about exception handling by
|
|
||||||
| reading docs.
|
|
||||||
|
|
|
||||||
| The exception handler extends a base `HttpExceptionHandler` which is not
|
|
||||||
| mandatory, however it can do lot of heavy lifting to handle the errors
|
|
||||||
| properly.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Logger from '@ioc:Adonis/Core/Logger'
|
|
||||||
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
|
|
||||||
|
|
||||||
export default class ExceptionHandler extends HttpExceptionHandler {
|
|
||||||
constructor() {
|
|
||||||
super(Logger)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import { BaseModel, column, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'
|
|
||||||
import MatchPlayer from './MatchPlayer'
|
|
||||||
import MatchTeam from './MatchTeam'
|
|
||||||
|
|
||||||
export default class Match extends BaseModel {
|
|
||||||
public static selfAssignPrimaryKey = true
|
|
||||||
|
|
||||||
@column({ isPrimary: true })
|
|
||||||
public id: string
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public gameId: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public map: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public gamemode: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public date: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public region: string
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public result: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public season: number
|
|
||||||
|
|
||||||
@column()
|
|
||||||
public gameDuration: number
|
|
||||||
|
|
||||||
@hasMany(() => MatchTeam)
|
|
||||||
public teams: HasMany<typeof MatchTeam>
|
|
||||||
|
|
||||||
@hasMany(() => MatchPlayer)
|
|
||||||
public players: HasMany<typeof MatchPlayer>
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { DateTime } from 'luxon'
|
|
||||||
import { BaseModel, column, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'
|
|
||||||
import SummonerMatchlist from './SummonerMatchlist'
|
|
||||||
import SummonerName from './SummonerName'
|
|
||||||
import MatchPlayer from './MatchPlayer'
|
|
||||||
|
|
||||||
export default class Summoner extends BaseModel {
|
|
||||||
public static selfAssignPrimaryKey = true
|
|
||||||
|
|
||||||
@column({ isPrimary: true })
|
|
||||||
public puuid: string
|
|
||||||
|
|
||||||
@column.dateTime({ autoCreate: true })
|
|
||||||
public createdAt: DateTime
|
|
||||||
|
|
||||||
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
|
||||||
public updatedAt: DateTime
|
|
||||||
|
|
||||||
@hasMany(() => SummonerMatchlist, {
|
|
||||||
localKey: 'puuid',
|
|
||||||
foreignKey: 'summonerPuuid',
|
|
||||||
})
|
|
||||||
public matchList: HasMany<typeof SummonerMatchlist>
|
|
||||||
|
|
||||||
@hasMany(() => MatchPlayer, {
|
|
||||||
localKey: 'puuid',
|
|
||||||
foreignKey: 'summonerPuuid',
|
|
||||||
})
|
|
||||||
public matches: HasMany<typeof MatchPlayer>
|
|
||||||
|
|
||||||
@hasMany(() => SummonerName, {
|
|
||||||
localKey: 'puuid',
|
|
||||||
foreignKey: 'summonerPuuid',
|
|
||||||
})
|
|
||||||
public names: HasMany<typeof SummonerName>
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
import Database from '@ioc:Adonis/Lucid/Database'
|
|
||||||
|
|
||||||
class MatchRepository {
|
|
||||||
private readonly JOIN_MATCHES = 'INNER JOIN matches ON matches.id = match_players.match_id'
|
|
||||||
private readonly JOIN_TEAMS =
|
|
||||||
'INNER JOIN match_teams ON match_players.match_id = match_teams.match_id AND match_players.team = match_teams.color'
|
|
||||||
private readonly JOIN_ALL = `${this.JOIN_MATCHES} ${this.JOIN_TEAMS}`
|
|
||||||
|
|
||||||
private readonly GLOBAL_FILTERS = `
|
|
||||||
match_players.summoner_puuid = :puuid
|
|
||||||
AND match_players.remake = 0
|
|
||||||
AND matches.gamemode NOT IN (800, 810, 820, 830, 840, 850, 2000, 2010, 2020)
|
|
||||||
`
|
|
||||||
|
|
||||||
public async recentActivity(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
to_timestamp(matches.date/1000)::date as day,
|
|
||||||
COUNT(match_players.id) as count
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
match_players.summoner_puuid = :puuid
|
|
||||||
GROUP BY
|
|
||||||
day
|
|
||||||
ORDER BY
|
|
||||||
day
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async globalStats(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
SUM(match_players.kills) as kills,
|
|
||||||
SUM(match_players.deaths) as deaths,
|
|
||||||
SUM(match_players.assists) as assists,
|
|
||||||
SUM(match_players.minions) as minions,
|
|
||||||
SUM(matches.game_duration) as time,
|
|
||||||
SUM(match_players.vision_score) as vision,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
AVG(match_players.kp) as kp,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
LIMIT
|
|
||||||
1
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
public async gamemodeStats(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
matches.gamemode as id,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
GROUP BY
|
|
||||||
matches.gamemode
|
|
||||||
ORDER BY
|
|
||||||
count DESC
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async roleStats(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
match_players.team_position as role,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
AND match_players.team_position != 0
|
|
||||||
GROUP BY
|
|
||||||
role
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async championStats(puuid: string, limit: number) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
match_players.champion_id as id,
|
|
||||||
SUM(match_players.assists) as assists,
|
|
||||||
SUM(match_players.deaths) as deaths,
|
|
||||||
SUM(match_players.kills) as kills,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
GROUP BY
|
|
||||||
match_players.champion_id
|
|
||||||
ORDER BY
|
|
||||||
count DESC, match_players.champion_id
|
|
||||||
LIMIT
|
|
||||||
:limit
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid, limit })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async championClassStats(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
match_players.champion_role as id,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
GROUP BY
|
|
||||||
match_players.champion_role
|
|
||||||
ORDER BY
|
|
||||||
count DESC
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async championCompleteStats(puuid: string, queue?: number, season?: number) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
match_players.champion_id as id,
|
|
||||||
SUM(match_players.assists) as assists,
|
|
||||||
SUM(match_players.deaths) as deaths,
|
|
||||||
SUM(match_players.kills) as kills,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses,
|
|
||||||
AVG(matches.game_duration)::int as "gameLength",
|
|
||||||
AVG(match_players.minions)::int as minions,
|
|
||||||
AVG(match_players.gold)::int as gold,
|
|
||||||
AVG(match_players.damage_dealt_champions)::int as "dmgChamp",
|
|
||||||
AVG(match_players.damage_taken)::int as "dmgTaken",
|
|
||||||
AVG(match_players.kp) as kp,
|
|
||||||
MAX(matches.date) as date
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
GROUP BY
|
|
||||||
match_players.champion_id
|
|
||||||
ORDER BY
|
|
||||||
count DESC, match_players.champion_id
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
public async mates(puuid: string) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
(array_agg(mates.summoner_name ORDER BY mates.match_id DESC))[1] as name,
|
|
||||||
COUNT(match_players.id) as count,
|
|
||||||
SUM(match_players.win) as wins,
|
|
||||||
SUM(match_players.loss) as losses
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_ALL}
|
|
||||||
INNER JOIN match_players as mates ON match_players.match_id = mates.match_id AND match_players.team = mates.team
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
GROUP BY
|
|
||||||
mates.summoner_puuid
|
|
||||||
ORDER BY
|
|
||||||
count DESC, wins DESC
|
|
||||||
LIMIT
|
|
||||||
15
|
|
||||||
`
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
|
|
||||||
// Remove the Summoner himself + unique game mates
|
|
||||||
return rows.splice(1).filter((row) => row.count > 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async records(puuid: string) {
|
|
||||||
const fields = [
|
|
||||||
'match_players.kills',
|
|
||||||
'match_players.deaths',
|
|
||||||
'match_players.assists',
|
|
||||||
'match_players.gold',
|
|
||||||
'matches.game_duration',
|
|
||||||
'match_players.minions',
|
|
||||||
'match_players.kda',
|
|
||||||
'match_players.damage_taken',
|
|
||||||
'match_players.damage_dealt_champions',
|
|
||||||
'match_players.damage_dealt_objectives',
|
|
||||||
'match_players.kp',
|
|
||||||
'match_players.vision_score',
|
|
||||||
'match_players.critical_strike',
|
|
||||||
'match_players.time_spent_living',
|
|
||||||
'match_players.heal',
|
|
||||||
'match_players.turret_kills',
|
|
||||||
'match_players.killing_spree',
|
|
||||||
'match_players.double_kills',
|
|
||||||
'match_players.triple_kills',
|
|
||||||
'match_players.quadra_kills',
|
|
||||||
'match_players.penta_kills',
|
|
||||||
]
|
|
||||||
|
|
||||||
const query = fields
|
|
||||||
.map((field) => {
|
|
||||||
return `
|
|
||||||
(SELECT
|
|
||||||
'${field}' AS what,
|
|
||||||
${field} AS amount,
|
|
||||||
match_players.win as result,
|
|
||||||
matches.id,
|
|
||||||
matches.date,
|
|
||||||
matches.gamemode,
|
|
||||||
match_players.champion_id
|
|
||||||
FROM
|
|
||||||
match_players
|
|
||||||
${this.JOIN_MATCHES}
|
|
||||||
WHERE
|
|
||||||
${this.GLOBAL_FILTERS}
|
|
||||||
ORDER BY
|
|
||||||
${field} DESC, matches.id
|
|
||||||
LIMIT
|
|
||||||
1)
|
|
||||||
`
|
|
||||||
})
|
|
||||||
.join('UNION ALL ')
|
|
||||||
|
|
||||||
const { rows } = await Database.rawQuery(query, { puuid })
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new MatchRepository()
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
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('RIOT_API_KEY') as string,
|
|
||||||
region: 'euw1',
|
|
||||||
requestOptions: {
|
|
||||||
retriesBeforeAbort: 3,
|
|
||||||
delayBeforeRetry: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import Jax from './src/Jax'
|
|
||||||
import { JAX_CONFIG } from './JaxConfig'
|
|
||||||
|
|
||||||
export = new Jax(JAX_CONFIG)
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
|
||||||
import RiotRateLimiter from 'riot-ratelimiter'
|
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
|
||||||
import JaxRequest from '../JaxRequest'
|
|
||||||
|
|
||||||
export interface CurrentGameInfoDTO {
|
|
||||||
gameId: number
|
|
||||||
gameType: string
|
|
||||||
gameStartTime: number
|
|
||||||
mapId: number
|
|
||||||
gameLength: number
|
|
||||||
platformId: string
|
|
||||||
gameMode: string
|
|
||||||
bannedChampions: BannedChampionDTO[]
|
|
||||||
gameQueueConfigId: number
|
|
||||||
observers: ObserverDTO
|
|
||||||
participants: CurrentGameParticipantDTO[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BannedChampionDTO {
|
|
||||||
pickTurn: number
|
|
||||||
championId: number
|
|
||||||
teamId: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ObserverDTO {
|
|
||||||
encryptionKey: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CurrentGameParticipantDTO {
|
|
||||||
championId: number
|
|
||||||
perks: PerksDTO
|
|
||||||
profileIconId: number
|
|
||||||
bot: boolean
|
|
||||||
teamId: number
|
|
||||||
summonerName: string
|
|
||||||
summonerId: string
|
|
||||||
spell1Id: number
|
|
||||||
spell2Id: number
|
|
||||||
gameCustomizationObjects: GameCustomizationObjectDTO[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PerksDTO {
|
|
||||||
perkIds: number[]
|
|
||||||
perkStyle: number
|
|
||||||
perkSubStyle: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GameCustomizationObjectDTO {
|
|
||||||
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): Promise<CurrentGameInfoDTO | undefined> {
|
|
||||||
return new JaxRequest(
|
|
||||||
region,
|
|
||||||
this.config,
|
|
||||||
`spectator/v4/active-games/by-summoner/${summonerID}`,
|
|
||||||
this.limiter,
|
|
||||||
0
|
|
||||||
).execute()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class SummonerEndpoint {
|
|
||||||
private config: JaxConfig
|
|
||||||
private limiter: RiotRateLimiter
|
|
||||||
|
|
||||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
|
||||||
this.config = config
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
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'
|
|
||||||
import MatchV4Endpoint from './Endpoints/MatchV4Endpoint'
|
|
||||||
import MatchlistV4Endpoint from './Endpoints/MatchlistV4Endpoint'
|
|
||||||
|
|
||||||
export default class Jax {
|
|
||||||
public key: string
|
|
||||||
public limiter: RiotRateLimiter
|
|
||||||
public config: JaxConfig
|
|
||||||
public League: LeagueEndpoint
|
|
||||||
public Match: MatchEndpoint
|
|
||||||
public MatchV4: MatchV4Endpoint
|
|
||||||
public Matchlist: MatchlistEndpoint
|
|
||||||
public MatchlistV4: MatchlistV4Endpoint
|
|
||||||
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.MatchV4 = new MatchV4Endpoint(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.Summoner = new SummonerEndpoint(this.config, this.limiter)
|
|
||||||
this.CDragon = new CDragonEndpoint(this.config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
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--
|
|
||||||
|
|
||||||
console.log('JAX ERROR')
|
|
||||||
console.log(rest?.cause?.code)
|
|
||||||
|
|
||||||
if (
|
|
||||||
statusCode !== 500 &&
|
|
||||||
statusCode !== 503 &&
|
|
||||||
statusCode !== 504 &&
|
|
||||||
rest?.cause?.code !== 'ETIMEDOUT'
|
|
||||||
) {
|
|
||||||
//
|
|
||||||
// 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(`URL ${url}: `)
|
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
import Jax from './Jax'
|
|
||||||
import { MatchlistDto } from './Jax/src/Endpoints/MatchlistEndpoint'
|
|
||||||
import { SummonerDTO } from './Jax/src/Endpoints/SummonerEndpoint'
|
|
||||||
import Summoner from 'App/Models/Summoner'
|
|
||||||
import Database from '@ioc:Adonis/Lucid/Database'
|
|
||||||
import MatchParser from 'App/Parsers/MatchParser'
|
|
||||||
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
|
|
||||||
import { SerializedMatch } from 'App/Serializers/SerializedTypes'
|
|
||||||
import Match from 'App/Models/Match'
|
|
||||||
import { notEmpty, tutorialQueues } from 'App/helpers'
|
|
||||||
|
|
||||||
class MatchService {
|
|
||||||
/**
|
|
||||||
* Add 100 matches at a time to MatchList until the stopFetching condition is true
|
|
||||||
* @param account of the summoner
|
|
||||||
* @param region of the summoner
|
|
||||||
* @param stopFetching condition to stop fetching the MatchList
|
|
||||||
*/
|
|
||||||
private async _fetchMatchListUntil(account: SummonerDTO, region: string, stopFetching: any) {
|
|
||||||
let matchList: MatchlistDto = []
|
|
||||||
let alreadyIn = false
|
|
||||||
let index = 0
|
|
||||||
do {
|
|
||||||
const newMatchList = await Jax.Matchlist.puuid(account.puuid, region, index)
|
|
||||||
// Error while fetching Riot API
|
|
||||||
if (!newMatchList) {
|
|
||||||
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].split('_')[0].toLowerCase() !== region.toLowerCase()) {
|
|
||||||
alreadyIn = true
|
|
||||||
}
|
|
||||||
index += 100
|
|
||||||
} while (!alreadyIn)
|
|
||||||
return matchList
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Update the full MatchList of the summoner
|
|
||||||
*/
|
|
||||||
public async updateMatchList(
|
|
||||||
account: SummonerDTO,
|
|
||||||
region: string,
|
|
||||||
summonerDB: Summoner
|
|
||||||
): Promise<MatchlistDto> {
|
|
||||||
console.time('matchList')
|
|
||||||
|
|
||||||
const currentMatchList = await summonerDB.related('matchList').query().orderBy('matchId', 'asc')
|
|
||||||
const currentMatchListIds = currentMatchList.map((m) => m.matchId)
|
|
||||||
|
|
||||||
const newMatchList = await this._fetchMatchListUntil(
|
|
||||||
account,
|
|
||||||
region,
|
|
||||||
(newMatchList: MatchlistDto) => {
|
|
||||||
return currentMatchListIds.some((id) => id === newMatchList[newMatchList.length - 1])
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const matchListToSave: MatchlistDto = []
|
|
||||||
for (const matchId of newMatchList.reverse()) {
|
|
||||||
if (!currentMatchListIds.some((id) => id === matchId)) {
|
|
||||||
matchListToSave.push(matchId)
|
|
||||||
currentMatchListIds.push(matchId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is new matchIds to save in database
|
|
||||||
if (matchListToSave.length) {
|
|
||||||
await Database.table('summoner_matchlist').multiInsert(
|
|
||||||
matchListToSave.map((id) => ({
|
|
||||||
match_id: id,
|
|
||||||
summoner_puuid: summonerDB.puuid,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.timeEnd('matchList')
|
|
||||||
return currentMatchListIds.reverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch list of matches for a specific Summoner
|
|
||||||
*/
|
|
||||||
public async getMatches(
|
|
||||||
region: string,
|
|
||||||
matchIds: string[],
|
|
||||||
puuid: string
|
|
||||||
): Promise<SerializedMatch[]> {
|
|
||||||
console.time('getMatches')
|
|
||||||
|
|
||||||
const matches: SerializedMatch[] = []
|
|
||||||
const matchesToGetFromRiot: MatchlistDto = []
|
|
||||||
for (let i = 0; i < matchIds.length; ++i) {
|
|
||||||
const matchSaved = await Match.query()
|
|
||||||
.where('id', matchIds[i])
|
|
||||||
.preload('teams')
|
|
||||||
.preload('players')
|
|
||||||
.first()
|
|
||||||
|
|
||||||
if (matchSaved) {
|
|
||||||
// TODO: Serialize match from DB + put it in Redis + push it in "matches"
|
|
||||||
matches.push(BasicMatchSerializer.serializeOneMatch(matchSaved, puuid))
|
|
||||||
} else {
|
|
||||||
matchesToGetFromRiot.push(matchIds[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const requests = matchesToGetFromRiot.map((gameId) => Jax.Match.get(gameId, region))
|
|
||||||
const matchesFromApi = await Promise.all(requests)
|
|
||||||
|
|
||||||
/* If we have to store some matches in the db */
|
|
||||||
if (matchesFromApi.length !== 0) {
|
|
||||||
// Remove bugged matches from the Riot API + tutorial games
|
|
||||||
const filteredMatches = matchesFromApi
|
|
||||||
.filter(notEmpty)
|
|
||||||
.filter(
|
|
||||||
(m) =>
|
|
||||||
!tutorialQueues.includes(m.info.queueId) &&
|
|
||||||
m.info.teams.length > 0 &&
|
|
||||||
m.info.participants.length > 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// Transform raw matches data
|
|
||||||
const parsedMatches: any = await MatchParser.parse(filteredMatches)
|
|
||||||
|
|
||||||
// TODO: Serialize match from DB + put it in Redis + push it in "matches"
|
|
||||||
const serializedMatches = BasicMatchSerializer.serialize(parsedMatches, puuid, true)
|
|
||||||
matches.push(...serializedMatches)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: check if we need to sort here
|
|
||||||
matches.sort((a, b) => (a.date < b.date ? 1 : -1))
|
|
||||||
console.timeEnd('getMatches')
|
|
||||||
return matches
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new MatchService()
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
import { sortTeamByRole } from 'App/helpers'
|
|
||||||
import { ChampionRoles, TeamPosition } from 'App/Parsers/ParsedType'
|
|
||||||
import MatchRepository from 'App/Repositories/MatchRepository'
|
|
||||||
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
|
|
||||||
|
|
||||||
class StatsService {
|
|
||||||
public async getRecentActivity(puuid: string) {
|
|
||||||
return MatchRepository.recentActivity(puuid)
|
|
||||||
}
|
|
||||||
public async getSummonerStats(puuid: string, season?: number) {
|
|
||||||
console.time('GLOBAL')
|
|
||||||
const globalStats = await MatchRepository.globalStats(puuid)
|
|
||||||
console.timeEnd('GLOBAL')
|
|
||||||
console.time('GAMEMODE')
|
|
||||||
const gamemodeStats = await MatchRepository.gamemodeStats(puuid)
|
|
||||||
console.timeEnd('GAMEMODE')
|
|
||||||
console.time('ROLE')
|
|
||||||
const roleStats = await MatchRepository.roleStats(puuid)
|
|
||||||
// Check if all roles are in the array
|
|
||||||
const roles = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY']
|
|
||||||
for (const role of roles) {
|
|
||||||
const findedRole = roleStats.find((r) => TeamPosition[r.role] === role)
|
|
||||||
if (findedRole) {
|
|
||||||
findedRole.role = TeamPosition[findedRole.role]
|
|
||||||
} else {
|
|
||||||
roleStats.push({
|
|
||||||
count: 0,
|
|
||||||
losses: 0,
|
|
||||||
role,
|
|
||||||
wins: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.timeEnd('ROLE')
|
|
||||||
console.time('CHAMPION')
|
|
||||||
const championStats = await MatchRepository.championStats(puuid, 5)
|
|
||||||
for (const champ of championStats) {
|
|
||||||
champ.champion = BasicMatchSerializer.getChampion(champ.id)
|
|
||||||
}
|
|
||||||
console.timeEnd('CHAMPION')
|
|
||||||
console.time('CHAMPION-CLASS')
|
|
||||||
const championClassStats = await MatchRepository.championClassStats(puuid)
|
|
||||||
for (const champ of championClassStats) {
|
|
||||||
champ.id = ChampionRoles[champ.id]
|
|
||||||
}
|
|
||||||
console.timeEnd('CHAMPION-CLASS')
|
|
||||||
console.time('MATES')
|
|
||||||
const mates = await MatchRepository.mates(puuid)
|
|
||||||
console.timeEnd('MATES')
|
|
||||||
|
|
||||||
console.time('RECENT_ACTIVITY')
|
|
||||||
const recentActivity = await MatchRepository.recentActivity(puuid)
|
|
||||||
console.timeEnd('RECENT_ACTIVITY')
|
|
||||||
|
|
||||||
return {
|
|
||||||
global: globalStats,
|
|
||||||
league: gamemodeStats,
|
|
||||||
role: roleStats.sort(sortTeamByRole),
|
|
||||||
champion: championStats,
|
|
||||||
class: championClassStats,
|
|
||||||
mates,
|
|
||||||
recentActivity,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new StatsService()
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
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'
|
|
||||||
import { PlayerRankParsed } from 'App/Parsers/ParsedType'
|
|
||||||
import MatchPlayerRank from 'App/Models/MatchPlayerRank'
|
|
||||||
|
|
||||||
export interface LeagueEntriesByQueue {
|
|
||||||
soloQ?: LeagueEntryByQueue
|
|
||||||
flex5v5?: LeagueEntryByQueue
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LeagueEntryByQueue extends LeagueEntryDTO {
|
|
||||||
fullRank: string
|
|
||||||
winrate: string
|
|
||||||
shortName: string | number
|
|
||||||
}
|
|
||||||
|
|
||||||
class SummonerService {
|
|
||||||
private readonly uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
|
|
||||||
public readonly leaguesNumbers = { I: 1, II: 2, III: 3, IV: 4 }
|
|
||||||
|
|
||||||
public getRankedShortName(rank: PlayerRankParsed | MatchPlayerRank) {
|
|
||||||
return this.uniqueLeagues.includes(rank.tier) ? rank.lp : rank.tier[0] + rank.rank
|
|
||||||
}
|
|
||||||
|
|
||||||
public getWinrate(wins: number, losses: number) {
|
|
||||||
return +((wins * 100) / (wins + losses)).toFixed(1) + '%'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = this.getWinrate(league.wins, league.losses)
|
|
||||||
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) {
|
|
||||||
await summonerDB.related('names').firstOrCreate({
|
|
||||||
name: account.name,
|
|
||||||
})
|
|
||||||
return summonerDB.related('names').query().select('name', 'created_at')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get ranked data for a specific Summoner
|
|
||||||
* @param account
|
|
||||||
* @param region
|
|
||||||
*/
|
|
||||||
public async getRanked(summonerId: string, region: string): Promise<LeagueEntriesByQueue> {
|
|
||||||
const ranked = await Jax.League.summonerID(summonerId, 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()
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class DetailedMatchValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
matchId: schema.string(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class MatchesIndexValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
puuid: schema.string(),
|
|
||||||
region: schema.string(),
|
|
||||||
matchIds: schema.array().members(schema.string()),
|
|
||||||
season: schema.number.optional(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { rules, schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class SummonerBasicValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
summoner: schema.string({}, [rules.regex(/^[0-9\p{L} _\.]+$/u)]),
|
|
||||||
region: schema.string(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class SummonerChampionValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
puuid: schema.string(),
|
|
||||||
queue: schema.number.optional(),
|
|
||||||
season: schema.number.optional(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class SummonerLiveValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
id: schema.string(),
|
|
||||||
region: schema.string(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class SummonerOverviewValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
puuid: schema.string(),
|
|
||||||
region: schema.string(),
|
|
||||||
season: schema.number.optional(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
||||||
|
|
||||||
export default class SummonerRecordValidator {
|
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
puuid: schema.string(),
|
|
||||||
season: schema.number.optional(),
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages = {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to help define a player's role
|
|
||||||
*/
|
|
||||||
export interface PlayerRole {
|
|
||||||
champion: number
|
|
||||||
jungle?: boolean
|
|
||||||
support?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 tutorial queues
|
|
||||||
*/
|
|
||||||
export const tutorialQueues = [2000, 2010, 2020]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SortableByRole {
|
|
||||||
role: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort array of Players by roles according to a specific order
|
|
||||||
* @param a first player
|
|
||||||
* @param b second player
|
|
||||||
*/
|
|
||||||
export function sortTeamByRole<T extends SortableByRole>(a: T, b: T) {
|
|
||||||
const sortingArr = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY']
|
|
||||||
return sortingArr.indexOf(a.role) - sortingArr.indexOf(b.role)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/46700791/9188650
|
|
||||||
export function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
|
|
||||||
if (value === null || value === undefined) return false
|
|
||||||
const testDummy: TValue = value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import { listDirectoryFiles } from '@adonisjs/core/build/standalone'
|
|
||||||
import Application from '@ioc:Adonis/Core/Application'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Exporting an array of commands
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Instead of manually exporting each file from this directory, we use the
|
|
||||||
| helper `listDirectoryFiles` to recursively collect and export an array
|
|
||||||
| of filenames.
|
|
||||||
|
|
|
||||||
| Couple of things to note:
|
|
||||||
|
|
|
||||||
| 1. The file path must be relative from the project root and not this directory.
|
|
||||||
| 2. We must ignore this file to avoid getting into an infinite loop
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index'])
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
/**
|
|
||||||
* Config source: https://git.io/JfefZ
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import proxyAddr from 'proxy-addr'
|
|
||||||
import Env from '@ioc:Adonis/Core/Env'
|
|
||||||
import { ServerConfig } from '@ioc:Adonis/Core/Server'
|
|
||||||
import { LoggerConfig } from '@ioc:Adonis/Core/Logger'
|
|
||||||
import { ProfilerConfig } from '@ioc:Adonis/Core/Profiler'
|
|
||||||
import { ValidatorConfig } from '@ioc:Adonis/Core/Validator'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application secret key
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The secret to encrypt and sign different values in your application.
|
|
||||||
| Make sure to keep the `APP_KEY` as an environment variable and secure.
|
|
||||||
|
|
|
||||||
| Note: Changing the application key for an existing app will make all
|
|
||||||
| the cookies invalid and also the existing encrypted data will not
|
|
||||||
| be decrypted.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
export const appKey: string = Env.get('APP_KEY')
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Http server configuration
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The configuration for the HTTP(s) server. Make sure to go through all
|
|
||||||
| the config properties to make keep server secure.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
export const http: ServerConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Allow method spoofing
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Method spoofing enables defining custom HTTP methods using a query string
|
|
||||||
| `_method`. This is usually required when you are making traditional
|
|
||||||
| form requests and wants to use HTTP verbs like `PUT`, `DELETE` and
|
|
||||||
| so on.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
allowMethodSpoofing: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Subdomain offset
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
subdomainOffset: 2,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Request Ids
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Setting this value to `true` will generate a unique request id for each
|
|
||||||
| HTTP request and set it as `x-request-id` header.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
generateRequestId: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Trusting proxy servers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define the proxy servers that AdonisJs must trust for reading `X-Forwarded`
|
|
||||||
| headers.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
trustProxy: proxyAddr.compile('loopback'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Generating Etag
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Whether or not to generate an etag for every response.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
etag: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| JSONP Callback
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
jsonpCallbackName: 'callback',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Cookie settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
cookie: {
|
|
||||||
domain: '',
|
|
||||||
path: '/',
|
|
||||||
maxAge: '2h',
|
|
||||||
httpOnly: true,
|
|
||||||
secure: false,
|
|
||||||
sameSite: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Force Content Negotiation
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The internals of the framework relies on the content negotiation to
|
|
||||||
| detect the best possible response type for a given HTTP request.
|
|
||||||
|
|
|
||||||
| However, it is a very common these days that API servers always wants to
|
|
||||||
| make response in JSON regardless of the existence of the `Accept` header.
|
|
||||||
|
|
|
||||||
| By setting `forceContentNegotiationTo = 'application/json'`, you negotiate
|
|
||||||
| with the server in advance to always return JSON without relying on the
|
|
||||||
| client to set the header explicitly.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
forceContentNegotiationTo: 'application/json',
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Logger
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
export const logger: LoggerConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application name
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The name of the application you want to add to the log. It is recommended
|
|
||||||
| to always have app name in every log line.
|
|
||||||
|
|
|
||||||
| The `APP_NAME` environment variable is automatically set by AdonisJS by
|
|
||||||
| reading the `name` property from the `package.json` file.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
name: Env.get('APP_NAME'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Toggle logger
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enable or disable logger application wide
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
enabled: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Logging level
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The level from which you want the logger to flush logs. It is recommended
|
|
||||||
| to make use of the environment variable, so that you can define log levels
|
|
||||||
| at deployment level and not code level.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
level: Env.get('LOG_LEVEL', 'info'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Pretty print
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| It is highly advised NOT to use `prettyPrint` in production, since it
|
|
||||||
| can have huge impact on performance.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
prettyPrint: Env.get('NODE_ENV') === 'development',
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Profiler
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
export const profiler: ProfilerConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Toggle profiler
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enable or disable profiler
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
enabled: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Blacklist actions/row labels
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define an array of actions or row labels that you want to disable from
|
|
||||||
| getting profiled.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
blacklist: [],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Whitelist actions/row labels
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define an array of actions or row labels that you want to whitelist for
|
|
||||||
| the profiler. When whitelist is defined, then `blacklist` is ignored.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
whitelist: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Validator
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Configure the global configuration for the validator. Here's the reference
|
|
||||||
| to the default config https://git.io/JT0WE
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
export const validator: ValidatorConfig = {}
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
/**
|
|
||||||
* Config source: https://git.io/Jfefn
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { BodyParserConfig } from '@ioc:Adonis/Core/BodyParser'
|
|
||||||
|
|
||||||
const bodyParserConfig: BodyParserConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| White listed methods
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| HTTP methods for which body parsing must be performed. It is a good practice
|
|
||||||
| to avoid body parsing for `GET` requests.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
whitelistedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| JSON parser settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The settings for the JSON parser. The types defines the request content
|
|
||||||
| types which gets processed by the JSON parser.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
json: {
|
|
||||||
encoding: 'utf-8',
|
|
||||||
limit: '1mb',
|
|
||||||
strict: true,
|
|
||||||
types: [
|
|
||||||
'application/json',
|
|
||||||
'application/json-patch+json',
|
|
||||||
'application/vnd.api+json',
|
|
||||||
'application/csp-report',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Form parser settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The settings for the `application/x-www-form-urlencoded` parser. The types
|
|
||||||
| defines the request content types which gets processed by the form parser.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
form: {
|
|
||||||
encoding: 'utf-8',
|
|
||||||
limit: '1mb',
|
|
||||||
queryString: {},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Convert empty strings to null
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Convert empty form fields to null. HTML forms results in field string
|
|
||||||
| value when the field is left blank. This option normalizes all the blank
|
|
||||||
| field values to "null"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
convertEmptyStringsToNull: true,
|
|
||||||
|
|
||||||
types: ['application/x-www-form-urlencoded'],
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Raw body parser settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Raw body just reads the request body stream as a plain text, which you
|
|
||||||
| can process by hand. This must be used when request body type is not
|
|
||||||
| supported by the body parser.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
raw: {
|
|
||||||
encoding: 'utf-8',
|
|
||||||
limit: '1mb',
|
|
||||||
queryString: {},
|
|
||||||
types: ['text/*'],
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Multipart parser settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The settings for the `multipart/form-data` parser. The types defines the
|
|
||||||
| request content types which gets processed by the form parser.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
multipart: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Auto process
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The auto process option will process uploaded files and writes them to
|
|
||||||
| the `tmp` folder. You can turn it off and then manually use the stream
|
|
||||||
| to pipe stream to a different destination.
|
|
||||||
|
|
|
||||||
| It is recommended to keep `autoProcess=true`. Unless you are processing bigger
|
|
||||||
| file sizes.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
autoProcess: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Files to be processed manually
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| You can turn off `autoProcess` for certain routes by defining
|
|
||||||
| routes inside the following array.
|
|
||||||
|
|
|
||||||
| NOTE: Make sure the route pattern starts with a leading slash.
|
|
||||||
|
|
|
||||||
| Correct
|
|
||||||
| ```js
|
|
||||||
| /projects/:id/file
|
|
||||||
| ```
|
|
||||||
|
|
|
||||||
| Incorrect
|
|
||||||
| ```js
|
|
||||||
| projects/:id/file
|
|
||||||
| ```
|
|
||||||
*/
|
|
||||||
processManually: [],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Temporary file name
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| When auto processing is on. We will use this method to compute the temporary
|
|
||||||
| file name. AdonisJs will compute a unique `tmpPath` for you automatically,
|
|
||||||
| However, you can also define your own custom method.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
// tmpFileName () {
|
|
||||||
// },
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Encoding
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Request body encoding
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
encoding: 'utf-8',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Convert empty strings to null
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Convert empty form fields to null. HTML forms results in field string
|
|
||||||
| value when the field is left blank. This option normalizes all the blank
|
|
||||||
| field values to "null"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
convertEmptyStringsToNull: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Max Fields
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The maximum number of fields allowed in the request body. The field includes
|
|
||||||
| text inputs and files both.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
maxFields: 1000,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Request body limit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The total limit to the multipart body. This includes all request files
|
|
||||||
| and fields data.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
limit: '20mb',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Types
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The types that will be considered and parsed as multipart body.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
types: ['multipart/form-data'],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default bodyParserConfig
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
/**
|
|
||||||
* Config source: https://git.io/JfefC
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { CorsConfig } from '@ioc:Adonis/Core/Cors'
|
|
||||||
|
|
||||||
const corsConfig: CorsConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Enabled
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| A boolean to enable or disable CORS integration from your AdonisJs
|
|
||||||
| application.
|
|
||||||
|
|
|
||||||
| Setting the value to `true` will enable the CORS for all HTTP request. However,
|
|
||||||
| you can define a function to enable/disable it on per request basis as well.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
enabled: true,
|
|
||||||
|
|
||||||
// You can also use a function that return true or false.
|
|
||||||
// enabled: (request) => request.url().startsWith('/api')
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Origin
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Set a list of origins to be allowed for `Access-Control-Allow-Origin`.
|
|
||||||
| The value can be one of the following:
|
|
||||||
|
|
|
||||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
|
||||||
|
|
|
||||||
| Boolean (true) - Allow current request origin.
|
|
||||||
| Boolean (false) - Disallow all.
|
|
||||||
| String - Comma separated list of allowed origins.
|
|
||||||
| Array - An array of allowed origins.
|
|
||||||
| String (*) - A wildcard (*) to allow all request origins.
|
|
||||||
| Function - Receives the current origin string and should return
|
|
||||||
| one of the above values.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
origin: (origin) => {
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (origin.includes('leaguestats.gg')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Methods
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| An array of allowed HTTP methods for CORS. The `Access-Control-Request-Method`
|
|
||||||
| is checked against the following list.
|
|
||||||
|
|
|
||||||
| Following is the list of default methods. Feel free to add more.
|
|
||||||
*/
|
|
||||||
methods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Headers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| List of headers to be allowed for `Access-Control-Allow-Headers` header.
|
|
||||||
| The value can be one of the following:
|
|
||||||
|
|
|
||||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers
|
|
||||||
|
|
|
||||||
| Boolean(true) - Allow all headers mentioned in `Access-Control-Request-Headers`.
|
|
||||||
| Boolean(false) - Disallow all headers.
|
|
||||||
| String - Comma separated list of allowed headers.
|
|
||||||
| Array - An array of allowed headers.
|
|
||||||
| Function - Receives the current header and should return one of the above values.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
headers: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Expose Headers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| A list of headers to be exposed by setting `Access-Control-Expose-Headers`.
|
|
||||||
| header. By default following 6 simple response headers are exposed.
|
|
||||||
|
|
|
||||||
| Cache-Control
|
|
||||||
| Content-Language
|
|
||||||
| Content-Type
|
|
||||||
| Expires
|
|
||||||
| Last-Modified
|
|
||||||
| Pragma
|
|
||||||
|
|
|
||||||
| In order to add more headers, simply define them inside the following array.
|
|
||||||
|
|
|
||||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
exposeHeaders: [
|
|
||||||
'cache-control',
|
|
||||||
'content-language',
|
|
||||||
'content-type',
|
|
||||||
'expires',
|
|
||||||
'last-modified',
|
|
||||||
'pragma',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credentials
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Toggle `Access-Control-Allow-Credentials` header. If value is set to `true`,
|
|
||||||
| then header will be set, otherwise not.
|
|
||||||
|
|
|
||||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
credentials: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| MaxAge
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define `Access-Control-Max-Age` header in seconds.
|
|
||||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
maxAge: 90,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default corsConfig
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
/**
|
|
||||||
* Config source: https://git.io/JfefW
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Env from '@ioc:Adonis/Core/Env'
|
|
||||||
import { HashConfig } from '@ioc:Adonis/Core/Hash'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Hash Config
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The `HashConfig` relies on the `HashList` interface which is
|
|
||||||
| defined inside `contracts` directory.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const hashConfig: HashConfig = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default hasher
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| By default we make use of the bcrypt hasher to hash values. However, feel
|
|
||||||
| free to change the default value
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
default: Env.get('HASH_DRIVER', 'argon'),
|
|
||||||
|
|
||||||
list: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Argon
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Argon mapping uses the `argon2` driver to hash values.
|
|
||||||
|
|
|
||||||
| Make sure you install the underlying dependency for this driver to work.
|
|
||||||
| https://www.npmjs.com/package/phc-argon2.
|
|
||||||
|
|
|
||||||
| npm install phc-argon2
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
argon: {
|
|
||||||
driver: 'argon2',
|
|
||||||
variant: 'id',
|
|
||||||
iterations: 3,
|
|
||||||
memory: 4096,
|
|
||||||
parallelism: 1,
|
|
||||||
saltSize: 16,
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Bcrypt
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Bcrypt mapping uses the `bcrypt` driver to hash values.
|
|
||||||
|
|
|
||||||
| Make sure you install the underlying dependency for this driver to work.
|
|
||||||
| https://www.npmjs.com/package/phc-bcrypt.
|
|
||||||
|
|
|
||||||
| npm install phc-bcrypt
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
bcrypt: {
|
|
||||||
driver: 'bcrypt',
|
|
||||||
rounds: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default hashConfig
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
/**
|
|
||||||
* Config source: https://git.io/JemcF
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Env from '@ioc:Adonis/Core/Env'
|
|
||||||
import { RedisConfig } from '@ioc:Adonis/Addons/Redis'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Redis configuration
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Following is the configuration used by the Redis provider to connect to
|
|
||||||
| the redis server and execute redis commands.
|
|
||||||
|
|
|
||||||
| Do make sure to pre-define the connections type inside `contracts/redis.ts`
|
|
||||||
| file for AdonisJs to recognize connections.
|
|
||||||
|
|
|
||||||
| Make sure to check `contracts/redis.ts` file for defining extra connections
|
|
||||||
*/
|
|
||||||
const redisConfig: RedisConfig = {
|
|
||||||
connection: Env.get('REDIS_CONNECTION'),
|
|
||||||
|
|
||||||
connections: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| The default connection
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The main connection you want to use to execute redis commands. The same
|
|
||||||
| connection will be used by the session provider, if you rely on the
|
|
||||||
| redis driver.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
local: {
|
|
||||||
host: Env.get('REDIS_HOST'),
|
|
||||||
port: Env.get('REDIS_PORT'),
|
|
||||||
password: Env.get('REDIS_PASSWORD', ''),
|
|
||||||
db: 0,
|
|
||||||
keyPrefix: '',
|
|
||||||
healthCheck: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default redisConfig
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Contract source: https://git.io/JTm6U
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this contract
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@ioc:Adonis/Core/Env' {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Getting types for validated environment variables
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The `default` export from the "../env.ts" file exports types for the
|
|
||||||
| validated environment variables. Here we merge them with the `EnvTypes`
|
|
||||||
| interface so that you can enjoy intellisense when using the "Env"
|
|
||||||
| module.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
type CustomTypes = typeof import('../env').default
|
|
||||||
interface EnvTypes extends CustomTypes {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
* Contract source: https://git.io/JfefG
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this contract
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@ioc:Adonis/Core/Event' {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Define typed events
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| You can define types for events inside the following interface and
|
|
||||||
| AdonisJS will make sure that all listeners and emit calls adheres
|
|
||||||
| to the defined types.
|
|
||||||
|
|
|
||||||
| For example:
|
|
||||||
|
|
|
||||||
| interface EventsList {
|
|
||||||
| 'new:user': UserModel
|
|
||||||
| }
|
|
||||||
|
|
|
||||||
| Now calling `Event.emit('new:user')` will statically ensure that passed value is
|
|
||||||
| an instance of the the UserModel only.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
interface EventsList {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Contract source: https://git.io/Jfefs
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this contract
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@ioc:Adonis/Core/Hash' {
|
|
||||||
interface HashersList {
|
|
||||||
bcrypt: {
|
|
||||||
config: BcryptConfig
|
|
||||||
implementation: BcryptContract
|
|
||||||
}
|
|
||||||
argon: {
|
|
||||||
config: ArgonConfig
|
|
||||||
implementation: ArgonContract
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/**
|
|
||||||
* Contract source: https://git.io/JemcN
|
|
||||||
*
|
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@ioc:Adonis/Addons/Redis' {
|
|
||||||
interface RedisConnectionsList {
|
|
||||||
local: RedisConnectionConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Validating Environment Variables
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| In this file we define the rules for validating environment variables.
|
|
||||||
| By performing validation we ensure that your application is running in
|
|
||||||
| a stable environment with correct configuration values.
|
|
||||||
|
|
|
||||||
| This file is read automatically by the framework during the boot lifecycle
|
|
||||||
| and hence do not rename or move this file to a different location.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Env from '@ioc:Adonis/Core/Env'
|
|
||||||
|
|
||||||
export default Env.rules({
|
|
||||||
HOST: Env.schema.string({ format: 'host' }),
|
|
||||||
PORT: Env.schema.number(),
|
|
||||||
APP_KEY: Env.schema.string(),
|
|
||||||
APP_NAME: Env.schema.string(),
|
|
||||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
|
||||||
NODE_ENV: Env.schema.enum(['development', 'production', 'testing'] as const),
|
|
||||||
|
|
||||||
DB_CONNECTION: Env.schema.string(),
|
|
||||||
PG_HOST: Env.schema.string({ format: 'host' }),
|
|
||||||
PG_PORT: Env.schema.number(),
|
|
||||||
PG_USER: Env.schema.string(),
|
|
||||||
PG_PASSWORD: Env.schema.string.optional(),
|
|
||||||
PG_DB_NAME: Env.schema.string(),
|
|
||||||
|
|
||||||
REDIS_CONNECTION: Env.schema.enum(['local'] as const),
|
|
||||||
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
|
||||||
REDIS_PORT: Env.schema.number(),
|
|
||||||
REDIS_PASSWORD: Env.schema.string.optional(),
|
|
||||||
|
|
||||||
RIOT_API_KEY: Env.schema.string(),
|
|
||||||
})
|
|
||||||
14567
server-v2/package-lock.json
generated
14567
server-v2/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
"name": "leaguestats",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "node ace serve --watch",
|
|
||||||
"build": "node ace build --production",
|
|
||||||
"start": "node server.js",
|
|
||||||
"lint": "eslint . --ext=.ts",
|
|
||||||
"format": "prettier --write ."
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@adonisjs/assembler": "^5.3.7",
|
|
||||||
"@types/pg": "^8.6.1",
|
|
||||||
"adonis-preset-ts": "^2.1.0",
|
|
||||||
"eslint": "^7.32.0",
|
|
||||||
"eslint-config-prettier": "^8.3.0",
|
|
||||||
"eslint-plugin-adonis": "^1.3.3",
|
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
|
||||||
"pino-pretty": "^7.0.0",
|
|
||||||
"prettier": "^2.4.0",
|
|
||||||
"typescript": "~4.2",
|
|
||||||
"youch": "^2.2.2",
|
|
||||||
"youch-terminal": "^1.1.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@adonisjs/core": "^5.3.4",
|
|
||||||
"@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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import { ApplicationContract } from '@ioc:Adonis/Core/Application'
|
|
||||||
|
|
||||||
export default class AppProvider {
|
|
||||||
constructor(protected app: ApplicationContract) {}
|
|
||||||
|
|
||||||
public register() {
|
|
||||||
// Register your own bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
public async boot() {
|
|
||||||
// IoC container is ready
|
|
||||||
|
|
||||||
// Load CDragon Service
|
|
||||||
const CDragon = await import('App/Services/CDragonService')
|
|
||||||
await CDragon.default.getContext()
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ready() {
|
|
||||||
// App is ready
|
|
||||||
}
|
|
||||||
|
|
||||||
public async shutdown() {
|
|
||||||
// Cleanup, since app is going down
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| AdonisJs Server
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The contents in this file is meant to bootstrap the AdonisJs application
|
|
||||||
| and start the HTTP server to accept incoming connections. You must avoid
|
|
||||||
| making this file dirty and instead make use of `lifecycle hooks` provided
|
|
||||||
| by AdonisJs service providers for custom code.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
import 'reflect-metadata'
|
|
||||||
import sourceMapSupport from 'source-map-support'
|
|
||||||
import { Ignitor } from '@adonisjs/core/build/standalone'
|
|
||||||
|
|
||||||
sourceMapSupport.install({ handleUncaughtExceptions: false })
|
|
||||||
|
|
||||||
new Ignitor(__dirname).httpServer().start()
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application middleware
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This file is used to define middleware for HTTP requests. You can register
|
|
||||||
| middleware as a `closure` or an IoC container binding. The bindings are
|
|
||||||
| preferred, since they keep this file clean.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Server from '@ioc:Adonis/Core/Server'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Global middleware
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| An array of global middleware, that will be executed in the order they
|
|
||||||
| are defined for every HTTP requests.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Server.middleware.register([() => import('@ioc:Adonis/Core/BodyParser')])
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Named middleware
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Named middleware are defined as key-value pair. The value is the namespace
|
|
||||||
| or middleware function and key is the alias. Later you can use these
|
|
||||||
| alias on individual routes. For example:
|
|
||||||
|
|
|
||||||
| { auth: () => import('App/Middleware/Auth') }
|
|
||||||
|
|
|
||||||
| and then use it as follows
|
|
||||||
|
|
|
||||||
| Route.get('dashboard', 'UserController.dashboard').middleware('auth')
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Server.middleware.registerNamed({})
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Routes
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This file is dedicated for defining HTTP routes. A single file is enough
|
|
||||||
| for majority of projects, however you can define routes in different
|
|
||||||
| files and just make sure to import them inside this file. For example
|
|
||||||
|
|
|
||||||
| Define routes in following two files
|
|
||||||
| ├── start/routes/cart.ts
|
|
||||||
| ├── start/routes/customer.ts
|
|
||||||
|
|
|
||||||
| and then import them inside `start/routes.ts` as follows
|
|
||||||
|
|
|
||||||
| import './routes/cart'
|
|
||||||
| import './routes/customer'
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
import HealthCheck from '@ioc:Adonis/Core/HealthCheck'
|
|
||||||
import Route from '@ioc:Adonis/Core/Route'
|
|
||||||
|
|
||||||
Route.get('/', async () => ({
|
|
||||||
hi: 'Hello World from LeagueStats V2 API',
|
|
||||||
uptime: process.uptime(),
|
|
||||||
}))
|
|
||||||
|
|
||||||
Route.get('/health', async () => ({ report: await HealthCheck.getReport() }))
|
|
||||||
|
|
||||||
Route.post('/summoner/basic', 'SummonersController.basic')
|
|
||||||
Route.post('/summoner/overview', 'SummonersController.overview')
|
|
||||||
|
|
||||||
Route.post('/summoner/champions', 'SummonersController.champions')
|
|
||||||
Route.post('/summoner/records', 'SummonersController.records')
|
|
||||||
Route.post('/summoner/live', 'SummonersController.liveMatchDetails')
|
|
||||||
|
|
||||||
Route.post('/match', 'MatchesController.index')
|
|
||||||
Route.post('/match/details', 'MatchesController.show')
|
|
||||||
Route.post('/match/details/ranks', 'MatchesController.showRanks')
|
|
||||||
|
|
||||||
Route.get('/cdragon/runes', 'CDragonController.runes')
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./node_modules/adonis-preset-ts/tsconfig",
|
|
||||||
"include": [
|
|
||||||
"**/*"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"build"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "build",
|
|
||||||
"rootDir": "./",
|
|
||||||
"sourceMap": true,
|
|
||||||
"paths": {
|
|
||||||
"App/*": [
|
|
||||||
"./app/*"
|
|
||||||
],
|
|
||||||
"Config/*": [
|
|
||||||
"./config/*"
|
|
||||||
],
|
|
||||||
"Contracts/*": [
|
|
||||||
"./contracts/*"
|
|
||||||
],
|
|
||||||
"Database/*": [
|
|
||||||
"./database/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"types": [
|
|
||||||
"@adonisjs/core",
|
|
||||||
"@adonisjs/repl",
|
|
||||||
"@adonisjs/lucid",
|
|
||||||
"@adonisjs/redis"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,28 +2,36 @@
|
||||||
"typescript": true,
|
"typescript": true,
|
||||||
"commands": [
|
"commands": [
|
||||||
"./commands",
|
"./commands",
|
||||||
"@adonisjs/core/build/commands",
|
"@adonisjs/core/build/commands/index.js",
|
||||||
"@zakodium/adonis-mongodb/lib/commands"
|
"@adonisjs/repl/build/commands",
|
||||||
|
"@adonisjs/lucid/build/commands"
|
||||||
],
|
],
|
||||||
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"App": "app",
|
"App": "app",
|
||||||
"Contracts": "contracts",
|
|
||||||
"Config": "config",
|
"Config": "config",
|
||||||
"Database": "database"
|
"Database": "database",
|
||||||
|
"Contracts": "contracts"
|
||||||
},
|
},
|
||||||
"preloads": [
|
"preloads": [
|
||||||
"./start/routes",
|
"./start/routes",
|
||||||
"./start/kernel"
|
"./start/kernel",
|
||||||
|
{
|
||||||
|
"file": "./start/events",
|
||||||
|
"environment": [
|
||||||
|
"console",
|
||||||
|
"repl",
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"providers": [
|
"providers": [
|
||||||
"./providers/AppProvider",
|
"./providers/AppProvider",
|
||||||
"@adonisjs/core",
|
"@adonisjs/core",
|
||||||
"@zakodium/adonis-mongodb",
|
"@adonisjs/lucid",
|
||||||
"@adonisjs/redis"
|
"@adonisjs/redis"
|
||||||
],
|
],
|
||||||
"metaFiles": [
|
"aceProviders": [
|
||||||
".env",
|
"@adonisjs/repl"
|
||||||
".adonisrc.json"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,18 @@ PORT=3333
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
|
DRIVE_DISK=local
|
||||||
|
|
||||||
MONGODB_URL=mongodb://localhost:27017
|
DB_CONNECTION=pg
|
||||||
MONGODB_DATABASE=leaguestats
|
PG_HOST=localhost
|
||||||
|
PG_PORT=5432
|
||||||
|
PG_USER=
|
||||||
|
PG_PASSWORD=
|
||||||
|
PG_DB_NAME=
|
||||||
|
|
||||||
REDIS_CONNECTION=local
|
REDIS_CONNECTION=local
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=127.0.0.1
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
REDIS_PASSWORD=
|
REDIS_PASSWORD=
|
||||||
|
|
||||||
API_KEY=RGAPI-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
RIOT_API_KEY=
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["plugin:adonis/typescriptApp", "prettier"],
|
||||||
"plugin:adonis/typescriptApp"
|
"plugins": ["prettier"],
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"max-len": [
|
"prettier/prettier": ["error"]
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"code": 130
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
server/.gitignore
vendored
1
server/.gitignore
vendored
|
|
@ -5,4 +5,3 @@ coverage
|
||||||
.DS_STORE
|
.DS_STORE
|
||||||
.env
|
.env
|
||||||
tmp
|
tmp
|
||||||
*.rdb
|
|
||||||
|
|
|
||||||
1
server/LeagueStatsSQL-Exported.diagram
Normal file
1
server/LeagueStatsSQL-Exported.diagram
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -3,17 +3,14 @@
|
||||||
| Ace Commands
|
| Ace Commands
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| This file is the entry point for running ace commands. For typescript
|
| This file is the entry point for running ace commands.
|
||||||
| projects, the ace commands will fallback to the compiled code and
|
|
||||||
| hence this file has to be executable by node directly.
|
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require('reflect-metadata')
|
require('reflect-metadata')
|
||||||
require('source-map-support').install({ handleUncaughtExceptions: false })
|
require('source-map-support').install({ handleUncaughtExceptions: false })
|
||||||
|
|
||||||
const { Ignitor } = require('@adonisjs/core/build/src/Ignitor')
|
const { Ignitor } = require('@adonisjs/core/build/standalone')
|
||||||
new Ignitor(__dirname)
|
new Ignitor(__dirname)
|
||||||
.ace()
|
.ace()
|
||||||
.handle(process.argv.slice(2))
|
.handle(process.argv.slice(2))
|
||||||
.catch(console.error)
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,294 @@
|
||||||
{"dump:rcfile":{"settings":{},"commandPath":"@adonisjs/core/build/commands/DumpRc","commandName":"dump:rcfile","description":"Dump contents of .adonisrc.json file along with defaults","args":[],"flags":[]},"list:routes":{"settings":{"loadApp":true},"commandPath":"@adonisjs/core/build/commands/ListRoutes","commandName":"list:routes","description":"List application routes","args":[],"flags":[{"name":"json","propertyName":"json","type":"boolean","description":"Output as JSON"}]},"generate:key":{"settings":{},"commandPath":"@adonisjs/core/build/commands/GenerateKey","commandName":"generate:key","description":"Generate a new APP_KEY secret","args":[],"flags":[]},"mongodb:make:migration":{"settings":{"loadApp":true},"commandPath":"@zakodium/adonis-mongodb/lib/commands/MongodbMakeMigration","commandName":"mongodb:make:migration","description":"Make a new migration file","args":[{"type":"string","propertyName":"name","name":"name","required":true,"description":"Name of the migration file"}],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Database connection to use for the migration"}]},"mongodb:migration:run":{"settings":{"loadApp":true},"commandPath":"@zakodium/adonis-mongodb/lib/commands/MongodbMigrate","commandName":"mongodb:migration:run","description":"Execute pending migrations","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Database connection to use for the migration"}]},"mongodb:migration:status":{"settings":{"loadApp":true},"commandPath":"@zakodium/adonis-mongodb/lib/commands/MongodbListMigrations","commandName":"mongodb:migration:status","description":"Show pending migrations","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Database connection to use for the migration"}]}}
|
{
|
||||||
|
"commands": {
|
||||||
|
"load:v4": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true,
|
||||||
|
"stayAlive": false
|
||||||
|
},
|
||||||
|
"commandPath": "./commands/LoadV4Matches",
|
||||||
|
"commandName": "load:v4",
|
||||||
|
"description": "Load matches for a given Summoner from the old Match-V4 endpoint",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"propertyName": "summoner",
|
||||||
|
"name": "summoner",
|
||||||
|
"required": true,
|
||||||
|
"description": "Summoner name to seach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"propertyName": "region",
|
||||||
|
"name": "region",
|
||||||
|
"required": true,
|
||||||
|
"description": "League region of the summoner"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": []
|
||||||
|
},
|
||||||
|
"dump:rcfile": {
|
||||||
|
"settings": {},
|
||||||
|
"commandPath": "@adonisjs/core/build/commands/DumpRc",
|
||||||
|
"commandName": "dump:rcfile",
|
||||||
|
"description": "Dump contents of .adonisrc.json file along with defaults",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": []
|
||||||
|
},
|
||||||
|
"list:routes": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/core/build/commands/ListRoutes",
|
||||||
|
"commandName": "list:routes",
|
||||||
|
"description": "List application routes",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "json",
|
||||||
|
"propertyName": "json",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Output as JSON"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"generate:key": {
|
||||||
|
"settings": {},
|
||||||
|
"commandPath": "@adonisjs/core/build/commands/GenerateKey",
|
||||||
|
"commandName": "generate:key",
|
||||||
|
"description": "Generate a new APP_KEY secret",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": []
|
||||||
|
},
|
||||||
|
"repl": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true,
|
||||||
|
"environment": "repl",
|
||||||
|
"stayAlive": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/repl/build/commands/AdonisRepl",
|
||||||
|
"commandName": "repl",
|
||||||
|
"description": "Start a new REPL session",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": []
|
||||||
|
},
|
||||||
|
"db:seed": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/DbSeed",
|
||||||
|
"commandName": "db:seed",
|
||||||
|
"description": "Execute database seeder files",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "connection",
|
||||||
|
"propertyName": "connection",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define a custom database connection for the seeders",
|
||||||
|
"alias": "c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "interactive",
|
||||||
|
"propertyName": "interactive",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Run seeders in interactive mode",
|
||||||
|
"alias": "i"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "files",
|
||||||
|
"propertyName": "files",
|
||||||
|
"type": "array",
|
||||||
|
"description": "Define a custom set of seeders files names to run",
|
||||||
|
"alias": "f"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"make:model": {
|
||||||
|
"settings": {},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/MakeModel",
|
||||||
|
"commandName": "make:model",
|
||||||
|
"description": "Make a new Lucid model",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"propertyName": "name",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"description": "Name of the model class"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "migration",
|
||||||
|
"propertyName": "migration",
|
||||||
|
"type": "boolean",
|
||||||
|
"alias": "m",
|
||||||
|
"description": "Generate the migration for the model"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller",
|
||||||
|
"propertyName": "controller",
|
||||||
|
"type": "boolean",
|
||||||
|
"alias": "c",
|
||||||
|
"description": "Generate the controller for the model"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"make:migration": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/MakeMigration",
|
||||||
|
"commandName": "make:migration",
|
||||||
|
"description": "Make a new migration file",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"propertyName": "name",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"description": "Name of the migration file"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "connection",
|
||||||
|
"propertyName": "connection",
|
||||||
|
"type": "string",
|
||||||
|
"description": "The connection flag is used to lookup the directory for the migration file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "folder",
|
||||||
|
"propertyName": "folder",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Pre-select a migration directory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "create",
|
||||||
|
"propertyName": "create",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define the table name for creating a new table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "table",
|
||||||
|
"propertyName": "table",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define the table name for altering an existing table"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"make:seeder": {
|
||||||
|
"settings": {},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/MakeSeeder",
|
||||||
|
"commandName": "make:seeder",
|
||||||
|
"description": "Make a new Seeder file",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"propertyName": "name",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"description": "Name of the seeder class"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": []
|
||||||
|
},
|
||||||
|
"migration:run": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/Migration/Run",
|
||||||
|
"commandName": "migration:run",
|
||||||
|
"description": "Run pending migrations",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "connection",
|
||||||
|
"propertyName": "connection",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define a custom database connection",
|
||||||
|
"alias": "c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "force",
|
||||||
|
"propertyName": "force",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Explicitly force to run migrations in production"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dry-run",
|
||||||
|
"propertyName": "dryRun",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Print SQL queries, instead of running the migrations"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"migration:rollback": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/Migration/Rollback",
|
||||||
|
"commandName": "migration:rollback",
|
||||||
|
"description": "Rollback migrations to a given batch number",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "connection",
|
||||||
|
"propertyName": "connection",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define a custom database connection",
|
||||||
|
"alias": "c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "force",
|
||||||
|
"propertyName": "force",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Explictly force to run migrations in production"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dry-run",
|
||||||
|
"propertyName": "dryRun",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Print SQL queries, instead of running the migrations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "batch",
|
||||||
|
"propertyName": "batch",
|
||||||
|
"type": "number",
|
||||||
|
"description": "Define custom batch number for rollback. Use 0 to rollback to initial state"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"migration:status": {
|
||||||
|
"settings": {
|
||||||
|
"loadApp": true
|
||||||
|
},
|
||||||
|
"commandPath": "@adonisjs/lucid/build/commands/Migration/Status",
|
||||||
|
"commandName": "migration:status",
|
||||||
|
"description": "Check migrations current status.",
|
||||||
|
"args": [],
|
||||||
|
"aliases": [],
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "connection",
|
||||||
|
"propertyName": "connection",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Define a custom database connection",
|
||||||
|
"alias": "c"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aliases": {}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Redis from '@ioc:Adonis/Addons/Redis'
|
import Redis from '@ioc:Adonis/Addons/Redis'
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||||
|
import RuneSerializer from 'App/Serializers/RuneSerializer'
|
||||||
import Jax from 'App/Services/Jax'
|
import Jax from 'App/Services/Jax'
|
||||||
import RuneTransformer from 'App/Transformers/RuneTransformer'
|
|
||||||
|
|
||||||
export default class CDragonController {
|
export default class CDragonController {
|
||||||
public async runes({ response }: HttpContextContract) {
|
public async runes({ response }: HttpContextContract) {
|
||||||
|
|
@ -16,8 +16,8 @@ export default class CDragonController {
|
||||||
const perkstyles = await Jax.CDragon.perkstyles()
|
const perkstyles = await Jax.CDragon.perkstyles()
|
||||||
|
|
||||||
const runesData = {
|
const runesData = {
|
||||||
perks: RuneTransformer.transformPerks(perks),
|
perks: RuneSerializer.serializePerks(perks),
|
||||||
perkstyles: RuneTransformer.transformStyles(perkstyles.styles),
|
perkstyles: RuneSerializer.serializeStyles(perkstyles.styles),
|
||||||
}
|
}
|
||||||
|
|
||||||
await Redis.set(cacheUrl, JSON.stringify(runesData), 'EX', 36000)
|
await Redis.set(cacheUrl, JSON.stringify(runesData), 'EX', 36000)
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,23 @@
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||||
import DetailedMatch, { DetailedMatchModel } from 'App/Models/DetailedMatch'
|
import Match from 'App/Models/Match'
|
||||||
import { ParticipantDetails } from 'App/Models/Match'
|
import MatchPlayerRankParser from 'App/Parsers/MatchPlayerRankParser'
|
||||||
import Summoner from 'App/Models/Summoner'
|
import DetailedMatchSerializer from 'App/Serializers/DetailedMatchSerializer'
|
||||||
import Jax from 'App/Services/Jax'
|
import MatchPlayerRankSerializer from 'App/Serializers/MatchPlayerRankSerializer'
|
||||||
import MatchService from 'App/Services/MatchService'
|
import MatchService from 'App/Services/MatchService'
|
||||||
import StatsService from 'App/Services/StatsService'
|
import StatsService from 'App/Services/StatsService'
|
||||||
import SummonerService from 'App/Services/SummonerService'
|
|
||||||
import DetailedMatchTransformer from 'App/Transformers/DetailedMatchTransformer'
|
|
||||||
import DetailedMatchValidator from 'App/Validators/DetailedMatchValidator'
|
import DetailedMatchValidator from 'App/Validators/DetailedMatchValidator'
|
||||||
import MatchesIndexValidator from 'App/Validators/MatchesIndexValidator'
|
import MatchesIndexValidator from 'App/Validators/MatchesIndexValidator'
|
||||||
|
|
||||||
export default class MatchesController {
|
export default class MatchesController {
|
||||||
/**
|
/**
|
||||||
* Get the soloQ rank of all the players of the team
|
* POST - Return data from matches searched by matchIds
|
||||||
* @param summoner all the data of the summoner
|
|
||||||
* @param region of the match
|
|
||||||
*/
|
|
||||||
private async getPlayerRank (summoner: ParticipantDetails, region: string) {
|
|
||||||
const account = await Jax.Summoner.summonerId(summoner.summonerId, region)
|
|
||||||
if (account) {
|
|
||||||
const ranked = await SummonerService.getRanked(account, region)
|
|
||||||
summoner.rank = ranked.soloQ ? (({ tier, shortName }) => ({ tier, shortName }))(ranked.soloQ) : null
|
|
||||||
} else {
|
|
||||||
summoner.rank = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return summoner
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST - Return data from matches searched by gameIds
|
|
||||||
* @param ctx
|
* @param ctx
|
||||||
*/
|
*/
|
||||||
public async index({ request, response }: HttpContextContract) {
|
public async index({ request, response }: HttpContextContract) {
|
||||||
console.log('More Matches Request')
|
const { puuid, region, matchIds, season } = await request.validate(MatchesIndexValidator)
|
||||||
const { puuid, accountId, region, gameIds, season } = await request.validate(MatchesIndexValidator)
|
const matches = await MatchService.getMatches(region, matchIds, puuid)
|
||||||
|
|
||||||
const summonerDB = await Summoner.findOne({ puuid })
|
|
||||||
if (!summonerDB) {
|
|
||||||
return response.json(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const matchesId = /^\d/.test(gameIds[0]) ? gameIds.map(id => `${region.toUpperCase()}_${id}`) : gameIds
|
|
||||||
const matches = await MatchService.getMatches(puuid, accountId, region, matchesId, summonerDB)
|
|
||||||
|
|
||||||
await summonerDB.save()
|
|
||||||
|
|
||||||
const stats = await StatsService.getSummonerStats(puuid, season)
|
const stats = await StatsService.getSummonerStats(puuid, season)
|
||||||
|
|
||||||
return response.json({
|
return response.json({
|
||||||
matches,
|
matches,
|
||||||
stats,
|
stats,
|
||||||
|
|
@ -60,25 +30,23 @@ export default class MatchesController {
|
||||||
*/
|
*/
|
||||||
public async show({ request, response }: HttpContextContract) {
|
public async show({ request, response }: HttpContextContract) {
|
||||||
console.time('MatchDetails')
|
console.time('MatchDetails')
|
||||||
const { gameId, region } = await request.validate(DetailedMatchValidator)
|
const { matchId } = await request.validate(DetailedMatchValidator)
|
||||||
|
|
||||||
let matchDetails: DetailedMatchModel
|
const match = await Match.query()
|
||||||
const alreadySaved = await DetailedMatch.findOne({ gameId, region })
|
.where('id', matchId)
|
||||||
|
.preload('teams')
|
||||||
|
.preload('players', (playersQuery) => {
|
||||||
|
playersQuery.preload('ranks')
|
||||||
|
})
|
||||||
|
.firstOrFail()
|
||||||
|
|
||||||
if (alreadySaved) {
|
const { match: matchDetails, ranksLoaded } = DetailedMatchSerializer.serializeOneMatch(match)
|
||||||
console.log('MATCH DETAILS ALREADY SAVED')
|
|
||||||
matchDetails = alreadySaved
|
|
||||||
} else {
|
|
||||||
const matchId = `${region.toUpperCase()}_${gameId}`
|
|
||||||
const match = await Jax.Match.get(matchId, region)
|
|
||||||
matchDetails = await DetailedMatchTransformer.transform(match)
|
|
||||||
await DetailedMatch.create(matchDetails)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.timeEnd('MatchDetails')
|
console.timeEnd('MatchDetails')
|
||||||
|
|
||||||
return response.json({
|
return response.json({
|
||||||
matchDetails,
|
matchDetails,
|
||||||
|
ranksLoaded,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,26 +56,12 @@ export default class MatchesController {
|
||||||
*/
|
*/
|
||||||
public async showRanks({ request, response }: HttpContextContract) {
|
public async showRanks({ request, response }: HttpContextContract) {
|
||||||
console.time('Ranks')
|
console.time('Ranks')
|
||||||
const { gameId, region } = await request.validate(DetailedMatchValidator)
|
const { matchId } = await request.validate(DetailedMatchValidator)
|
||||||
|
const match = await Match.query().where('id', matchId).preload('players').firstOrFail()
|
||||||
|
const parsedRanks = await MatchPlayerRankParser.parse(match)
|
||||||
|
const serializedRanks = MatchPlayerRankSerializer.serialize(parsedRanks)
|
||||||
|
|
||||||
let matchDetails = await DetailedMatch.findOne({ gameId, region })
|
|
||||||
|
|
||||||
if (!matchDetails) {
|
|
||||||
return response.json(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestsBlue = matchDetails.blueTeam.players.map(p => this.getPlayerRank(p, region))
|
|
||||||
matchDetails.blueTeam.players = await Promise.all(requestsBlue)
|
|
||||||
|
|
||||||
const requestsRed = matchDetails.redTeam.players.map(p => this.getPlayerRank(p, region))
|
|
||||||
matchDetails.redTeam.players = await Promise.all(requestsRed)
|
|
||||||
|
|
||||||
matchDetails.save()
|
|
||||||
console.timeEnd('Ranks')
|
console.timeEnd('Ranks')
|
||||||
|
return response.json(serializedRanks)
|
||||||
return response.json({
|
|
||||||
blueTeam: matchDetails.blueTeam.players,
|
|
||||||
redTeam: matchDetails.redTeam.players,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||||
import { getCurrentSeason } from 'App/helpers'
|
import { getCurrentSeason } from 'App/helpers'
|
||||||
import Summoner from 'App/Models/Summoner'
|
import Summoner from 'App/Models/Summoner'
|
||||||
import MatchRepository from 'App/Repositories/MatchRepository'
|
import MatchRepository from 'App/Repositories/MatchRepository'
|
||||||
|
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
|
||||||
|
import LiveMatchSerializer from 'App/Serializers/LiveMatchSerializer'
|
||||||
import Jax from 'App/Services/Jax'
|
import Jax from 'App/Services/Jax'
|
||||||
import MatchService from 'App/Services/MatchService'
|
import MatchService from 'App/Services/MatchService'
|
||||||
import StatsService from 'App/Services/StatsService'
|
import StatsService from 'App/Services/StatsService'
|
||||||
import SummonerService from 'App/Services/SummonerService'
|
import SummonerService from 'App/Services/SummonerService'
|
||||||
import LiveMatchTransformer from 'App/Transformers/LiveMatchTransformer'
|
|
||||||
import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator'
|
import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator'
|
||||||
import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator'
|
import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator'
|
||||||
import SummonerLiveValidator from 'App/Validators/SummonerLiveValidator'
|
import SummonerLiveValidator from 'App/Validators/SummonerLiveValidator'
|
||||||
|
|
@ -14,21 +15,8 @@ import SummonerOverviewValidator from 'App/Validators/SummonerOverviewValidator'
|
||||||
import SummonerRecordValidator from 'App/Validators/SummonerRecordValidator'
|
import SummonerRecordValidator from 'App/Validators/SummonerRecordValidator'
|
||||||
|
|
||||||
export default class SummonersController {
|
export default class SummonersController {
|
||||||
/**
|
|
||||||
* Get all played seasons for a summoner
|
|
||||||
* @param puuid of the summoner
|
|
||||||
*/
|
|
||||||
private async getSeasons (puuid: string): Promise<number[]> {
|
|
||||||
const seasons = await MatchRepository.seasons(puuid)
|
|
||||||
return seasons.length ? seasons.map(s => s._id) : [getCurrentSeason()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST: get basic summoner data
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async basic({ request, response }: HttpContextContract) {
|
public async basic({ request, response }: HttpContextContract) {
|
||||||
console.time('all')
|
console.time('BASIC_REQUEST')
|
||||||
const { summoner, region } = await request.validate(SummonerBasicValidator)
|
const { summoner, region } = await request.validate(SummonerBasicValidator)
|
||||||
const finalJSON: any = {}
|
const finalJSON: any = {}
|
||||||
|
|
||||||
|
|
@ -38,24 +26,20 @@ export default class SummonersController {
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return response.json(null)
|
return response.json(null)
|
||||||
}
|
}
|
||||||
account.region = region
|
|
||||||
finalJSON.account = account
|
finalJSON.account = account
|
||||||
|
|
||||||
// Summoner in DB
|
// Summoner in DB
|
||||||
let summonerDB = await Summoner.findOne({ puuid: account.puuid })
|
const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid })
|
||||||
if (!summonerDB) {
|
|
||||||
summonerDB = await Summoner.create({ puuid: account.puuid })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Summoner names
|
// Summoner names
|
||||||
finalJSON.account.names = SummonerService.getAllSummonerNames(account, summonerDB)
|
finalJSON.account.names = await SummonerService.getAllSummonerNames(account, summonerDB)
|
||||||
|
|
||||||
// MATCH LIST
|
// MATCH LIST
|
||||||
await MatchService.updateMatchList(account, summonerDB)
|
finalJSON.matchList = await MatchService.updateMatchList(account, region, summonerDB)
|
||||||
finalJSON.matchList = summonerDB.matchList
|
|
||||||
|
|
||||||
// All seasons the summoner has played
|
// All seasons the summoner has played
|
||||||
finalJSON.seasons = await this.getSeasons(account.puuid)
|
// TODO: check if there is a way to do that with V5...
|
||||||
|
finalJSON.seasons = [getCurrentSeason()]
|
||||||
|
|
||||||
// CURRENT GAME
|
// CURRENT GAME
|
||||||
const currentGame = await Jax.Spectator.summonerID(account.id, region)
|
const currentGame = await Jax.Spectator.summonerID(account.id, region)
|
||||||
|
|
@ -63,52 +47,44 @@ export default class SummonersController {
|
||||||
finalJSON.current = currentGame
|
finalJSON.current = currentGame
|
||||||
|
|
||||||
// RANKED STATS
|
// RANKED STATS
|
||||||
finalJSON.ranked = await SummonerService.getRanked(account, region)
|
finalJSON.ranked = await SummonerService.getRanked(account.id, region)
|
||||||
|
|
||||||
// SAVE IN DB
|
// RECENT ACTIVITY
|
||||||
await summonerDB.save()
|
finalJSON.recentActivity = await StatsService.getRecentActivity(account.puuid)
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
console.log('username not found')
|
console.log(e)
|
||||||
console.log(error)
|
console.timeEnd('BASIC_REQUEST')
|
||||||
return response.json(null)
|
return response.json(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.timeEnd('all')
|
console.timeEnd('BASIC_REQUEST')
|
||||||
return response.json(finalJSON)
|
return response.json(finalJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* POST: get overview view summoner data
|
|
||||||
* @param ctx
|
|
||||||
*/
|
|
||||||
public async overview({ request, response }: HttpContextContract) {
|
public async overview({ request, response }: HttpContextContract) {
|
||||||
console.time('overview')
|
console.time('OVERVIEW_REQUEST')
|
||||||
const { puuid, accountId, region, season } = await request.validate(SummonerOverviewValidator)
|
const { puuid, region, season } = await request.validate(SummonerOverviewValidator)
|
||||||
const finalJSON: any = {}
|
const finalJSON: any = {}
|
||||||
|
|
||||||
// Summoner in DB
|
// Summoner in DB
|
||||||
let summonerDB = await Summoner.findOne({ puuid: puuid })
|
const summonerDB = await Summoner.firstOrCreate({ puuid: puuid })
|
||||||
if (!summonerDB) {
|
|
||||||
summonerDB = await Summoner.create({ puuid: puuid })
|
|
||||||
}
|
|
||||||
|
|
||||||
// MATCHES BASIC
|
// MATCHES BASIC
|
||||||
const gameIds = summonerDB.matchList!.slice(0)
|
const matchlist = await summonerDB
|
||||||
// .filter(m => {
|
.related('matchList')
|
||||||
// return season ? m.seasonMatch === season : true // TODO: filter by season
|
.query()
|
||||||
// })
|
.select('matchId')
|
||||||
.slice(0, 10)
|
.orderBy('matchId', 'desc')
|
||||||
finalJSON.matchesDetails = await MatchService.getMatches(puuid, accountId, region, gameIds, summonerDB)
|
.limit(10)
|
||||||
|
const matchIds = matchlist.map((m) => m.matchId)
|
||||||
|
|
||||||
|
finalJSON.matchesDetails = await MatchService.getMatches(region, matchIds, puuid)
|
||||||
|
|
||||||
// STATS
|
|
||||||
console.time('STATS')
|
console.time('STATS')
|
||||||
finalJSON.stats = await StatsService.getSummonerStats(puuid, season)
|
finalJSON.stats = await StatsService.getSummonerStats(puuid, season)
|
||||||
console.timeEnd('STATS')
|
console.timeEnd('STATS')
|
||||||
|
|
||||||
// SAVE IN DB
|
console.timeEnd('OVERVIEW_REQUEST')
|
||||||
await summonerDB.save()
|
|
||||||
|
|
||||||
console.timeEnd('overview')
|
|
||||||
return response.json(finalJSON)
|
return response.json(finalJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,8 +96,14 @@ export default class SummonersController {
|
||||||
console.time('championsRequest')
|
console.time('championsRequest')
|
||||||
const { puuid, queue, season } = await request.validate(SummonerChampionValidator)
|
const { puuid, queue, season } = await request.validate(SummonerChampionValidator)
|
||||||
const championStats = await MatchRepository.championCompleteStats(puuid, queue, season)
|
const championStats = await MatchRepository.championCompleteStats(puuid, queue, season)
|
||||||
|
const championStatsSerialized = championStats.map((champion) => {
|
||||||
|
return {
|
||||||
|
...champion,
|
||||||
|
champion: BasicMatchSerializer.getChampion(champion.id),
|
||||||
|
}
|
||||||
|
})
|
||||||
console.timeEnd('championsRequest')
|
console.timeEnd('championsRequest')
|
||||||
return response.json(championStats)
|
return response.json(championStatsSerialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -131,9 +113,16 @@ export default class SummonersController {
|
||||||
public async records({ request, response }: HttpContextContract) {
|
public async records({ request, response }: HttpContextContract) {
|
||||||
console.time('recordsRequest')
|
console.time('recordsRequest')
|
||||||
const { puuid, season } = await request.validate(SummonerRecordValidator)
|
const { puuid, season } = await request.validate(SummonerRecordValidator)
|
||||||
const records = await MatchRepository.records(puuid, season)
|
const records = await MatchRepository.records(puuid)
|
||||||
|
const recordsSerialized = records.map((record) => {
|
||||||
|
return {
|
||||||
|
...record,
|
||||||
|
what: record.what.split('.')[1],
|
||||||
|
champion: BasicMatchSerializer.getChampion(record.champion_id),
|
||||||
|
}
|
||||||
|
})
|
||||||
console.timeEnd('recordsRequest')
|
console.timeEnd('recordsRequest')
|
||||||
return response.json(records)
|
return response.json(recordsSerialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -145,15 +134,15 @@ export default class SummonersController {
|
||||||
const { id, region } = await request.validate(SummonerLiveValidator)
|
const { id, region } = await request.validate(SummonerLiveValidator)
|
||||||
|
|
||||||
// CURRENT GAME
|
// CURRENT GAME
|
||||||
let currentGame = await Jax.Spectator.summonerID(id, region)
|
const currentGame = await Jax.Spectator.summonerID(id, region)
|
||||||
|
|
||||||
if (!currentGame) {
|
if (!currentGame) {
|
||||||
return response.json(null)
|
return response.json(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentGame = await LiveMatchTransformer.transform(currentGame, { region })
|
const currentGameSerialized = await LiveMatchSerializer.serializeOneMatch(currentGame, region)
|
||||||
console.timeEnd('liveMatchDetails')
|
console.timeEnd('liveMatchDetails')
|
||||||
|
|
||||||
return response.json(currentGame)
|
return response.json(currentGameSerialized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
import { Model } from '@ioc:Mongodb/Model'
|
|
||||||
import { Champion, ParticipantDetails } from 'App/Models/Match'
|
|
||||||
|
|
||||||
export interface DetailedMatchModel {
|
|
||||||
gameId: number,
|
|
||||||
season: number,
|
|
||||||
blueTeam: Team,
|
|
||||||
redTeam: Team,
|
|
||||||
map: number,
|
|
||||||
gamemode: number,
|
|
||||||
date: number,
|
|
||||||
region: string,
|
|
||||||
time: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Team {
|
|
||||||
bans: Ban[],
|
|
||||||
barons: number,
|
|
||||||
color: string,
|
|
||||||
dragons: number,
|
|
||||||
inhibitors: number,
|
|
||||||
players: ParticipantDetails[],
|
|
||||||
result: string,
|
|
||||||
riftHerald: number,
|
|
||||||
teamStats: TeamStats,
|
|
||||||
towers: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Ban {
|
|
||||||
championId: number,
|
|
||||||
pickTurn: number,
|
|
||||||
champion: Champion<null | number, null | string>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TeamStats {
|
|
||||||
kills: number,
|
|
||||||
deaths: number,
|
|
||||||
assists: number,
|
|
||||||
gold: number,
|
|
||||||
dmgChamp: number,
|
|
||||||
dmgObj: number,
|
|
||||||
dmgTaken: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class DetailedMatch extends Model implements DetailedMatchModel {
|
|
||||||
public static collectionName = 'detailed_matches'
|
|
||||||
|
|
||||||
public gameId: number
|
|
||||||
public season: number
|
|
||||||
public blueTeam: Team
|
|
||||||
public redTeam: Team
|
|
||||||
public map: number
|
|
||||||
public gamemode: number
|
|
||||||
public date: number
|
|
||||||
public region: string
|
|
||||||
public time: number
|
|
||||||
}
|
|
||||||
|
|
@ -1,140 +1,40 @@
|
||||||
import { Model } from '@ioc:Mongodb/Model'
|
import { BaseModel, column, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'
|
||||||
|
import MatchPlayer from './MatchPlayer'
|
||||||
|
import MatchTeam from './MatchTeam'
|
||||||
|
|
||||||
export interface MatchModel extends ParticipantDetails {
|
export default class Match extends BaseModel {
|
||||||
account_id: string,
|
public static selfAssignPrimaryKey = true
|
||||||
summoner_puuid: string,
|
|
||||||
gameId: number,
|
|
||||||
result: string,
|
|
||||||
allyTeam: ParticipantBasic[],
|
|
||||||
enemyTeam: ParticipantBasic[],
|
|
||||||
map: number,
|
|
||||||
gamemode: number,
|
|
||||||
date: number,
|
|
||||||
region: string,
|
|
||||||
season: number,
|
|
||||||
time: number,
|
|
||||||
newMatch?: boolean,
|
|
||||||
|
|
||||||
// V5
|
@column({ isPrimary: true })
|
||||||
matchId: string,
|
public id: string
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParticipantDetails {
|
@column()
|
||||||
name: string,
|
|
||||||
summonerId: string,
|
|
||||||
champion: Champion,
|
|
||||||
role: string,
|
|
||||||
primaryRune: string | null,
|
|
||||||
secondaryRune: string | null,
|
|
||||||
level: number,
|
|
||||||
items: (Item | null)[],
|
|
||||||
firstSum: SummonerSpell | number | null,
|
|
||||||
secondSum: SummonerSpell | number | null,
|
|
||||||
stats: Stats,
|
|
||||||
percentStats?: PercentStats
|
|
||||||
rank?: Rank | null,
|
|
||||||
perks?: Perks
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Champion<T = number, U = string> {
|
|
||||||
id: number | T,
|
|
||||||
name: string | U,
|
|
||||||
alias?: string,
|
|
||||||
roles?: string[],
|
|
||||||
icon?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SummonerSpell {
|
|
||||||
name: string,
|
|
||||||
description: string,
|
|
||||||
icon: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Rank {
|
|
||||||
tier: string,
|
|
||||||
shortName: string | number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Perks {
|
|
||||||
primaryStyle: number;
|
|
||||||
secondaryStyle: number;
|
|
||||||
selected: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParticipantBasic {
|
|
||||||
account_id: string,
|
|
||||||
name: string,
|
|
||||||
role: string,
|
|
||||||
champion: Champion
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Item {
|
|
||||||
image: string,
|
|
||||||
name: string,
|
|
||||||
description: string,
|
|
||||||
price: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Stats {
|
|
||||||
kills: number,
|
|
||||||
deaths: number,
|
|
||||||
assists: number,
|
|
||||||
minions: number,
|
|
||||||
vision: number,
|
|
||||||
gold: number,
|
|
||||||
dmgChamp: number,
|
|
||||||
dmgObj: number,
|
|
||||||
dmgTaken: number,
|
|
||||||
kda: number | string,
|
|
||||||
realKda: number,
|
|
||||||
criticalStrike?: number,
|
|
||||||
killingSpree?: number,
|
|
||||||
doubleKills?: number,
|
|
||||||
tripleKills?: number,
|
|
||||||
quadraKills?: number,
|
|
||||||
pentaKills?: number,
|
|
||||||
heal?: number,
|
|
||||||
towers?: number,
|
|
||||||
longestLiving?: number,
|
|
||||||
kp: number | string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PercentStats {
|
|
||||||
minions: number,
|
|
||||||
vision: number,
|
|
||||||
gold: string,
|
|
||||||
dmgChamp: string,
|
|
||||||
dmgObj: string,
|
|
||||||
dmgTaken: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Match extends Model implements MatchModel {
|
|
||||||
public static collectionName = 'matches'
|
|
||||||
|
|
||||||
public account_id: string
|
|
||||||
public summoner_puuid: string
|
|
||||||
public gameId: number
|
public gameId: number
|
||||||
public result: string
|
|
||||||
public allyTeam: ParticipantBasic[]
|
|
||||||
public enemyTeam: ParticipantBasic[]
|
|
||||||
public map: number
|
|
||||||
public gamemode: number
|
|
||||||
public date: number
|
|
||||||
public region: string
|
|
||||||
public season: number
|
|
||||||
public time: number
|
|
||||||
public name: string
|
|
||||||
public summonerId: string
|
|
||||||
public champion: Champion
|
|
||||||
public role: string
|
|
||||||
public primaryRune: string
|
|
||||||
public secondaryRune: string
|
|
||||||
public level: number
|
|
||||||
public items: Item[]
|
|
||||||
public firstSum: number
|
|
||||||
public secondSum: number
|
|
||||||
public stats: Stats
|
|
||||||
|
|
||||||
// V5
|
@column()
|
||||||
public matchId: string
|
public map: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public gamemode: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public date: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public region: string
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public result: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public season: number
|
||||||
|
|
||||||
|
@column()
|
||||||
|
public gameDuration: number
|
||||||
|
|
||||||
|
@hasMany(() => MatchTeam)
|
||||||
|
public teams: HasMany<typeof MatchTeam>
|
||||||
|
|
||||||
|
@hasMany(() => MatchPlayer)
|
||||||
|
public players: HasMany<typeof MatchPlayer>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,36 @@
|
||||||
import { Model } from '@ioc:Mongodb/Model'
|
import { DateTime } from 'luxon'
|
||||||
import { MatchlistDto } from 'App/Services/Jax/src/Endpoints/MatchlistEndpoint'
|
import { BaseModel, column, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'
|
||||||
|
import SummonerMatchlist from './SummonerMatchlist'
|
||||||
|
import SummonerName from './SummonerName'
|
||||||
|
import MatchPlayer from './MatchPlayer'
|
||||||
|
|
||||||
export interface SummonerModel {
|
export default class Summoner extends BaseModel {
|
||||||
puuid: string,
|
public static selfAssignPrimaryKey = true
|
||||||
matchList?: MatchlistDto,
|
|
||||||
names?: SummonerNames[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SummonerNames {
|
|
||||||
name: string,
|
|
||||||
date: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Summoner extends Model implements SummonerModel {
|
|
||||||
public static collectionName = 'summoners'
|
|
||||||
|
|
||||||
|
@column({ isPrimary: true })
|
||||||
public puuid: string
|
public puuid: string
|
||||||
public matchList?: MatchlistDto
|
|
||||||
public names?: SummonerNames[]
|
@column.dateTime({ autoCreate: true })
|
||||||
|
public createdAt: DateTime
|
||||||
|
|
||||||
|
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||||
|
public updatedAt: DateTime
|
||||||
|
|
||||||
|
@hasMany(() => SummonerMatchlist, {
|
||||||
|
localKey: 'puuid',
|
||||||
|
foreignKey: 'summonerPuuid',
|
||||||
|
})
|
||||||
|
public matchList: HasMany<typeof SummonerMatchlist>
|
||||||
|
|
||||||
|
@hasMany(() => MatchPlayer, {
|
||||||
|
localKey: 'puuid',
|
||||||
|
foreignKey: 'summonerPuuid',
|
||||||
|
})
|
||||||
|
public matches: HasMany<typeof MatchPlayer>
|
||||||
|
|
||||||
|
@hasMany(() => SummonerName, {
|
||||||
|
localKey: 'puuid',
|
||||||
|
foreignKey: 'summonerPuuid',
|
||||||
|
})
|
||||||
|
public names: HasMany<typeof SummonerName>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,337 +1,257 @@
|
||||||
import mongodb from '@ioc:Mongodb/Database'
|
import Database from '@ioc:Adonis/Lucid/Database'
|
||||||
import { Collection } from 'mongodb'
|
|
||||||
|
|
||||||
class MatchRepository {
|
class MatchRepository {
|
||||||
private collection: Collection
|
private readonly JOIN_MATCHES = 'INNER JOIN matches ON matches.id = match_players.match_id'
|
||||||
|
private readonly JOIN_TEAMS =
|
||||||
|
'INNER JOIN match_teams ON match_players.match_id = match_teams.match_id AND match_players.team = match_teams.color'
|
||||||
|
private readonly JOIN_ALL = `${this.JOIN_MATCHES} ${this.JOIN_TEAMS}`
|
||||||
|
|
||||||
constructor () {
|
private readonly GLOBAL_FILTERS = `
|
||||||
this.getCollection()
|
match_players.summoner_puuid = :puuid
|
||||||
|
AND match_players.remake = 0
|
||||||
|
AND matches.gamemode NOT IN (800, 810, 820, 830, 840, 850, 2000, 2010, 2020)
|
||||||
|
`
|
||||||
|
|
||||||
|
public async recentActivity(puuid: string) {
|
||||||
|
const query = `
|
||||||
|
SELECT
|
||||||
|
to_timestamp(matches.date/1000)::date as day,
|
||||||
|
COUNT(match_players.id) as count
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
match_players.summoner_puuid = :puuid
|
||||||
|
GROUP BY
|
||||||
|
day
|
||||||
|
ORDER BY
|
||||||
|
day
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async globalStats(puuid: string) {
|
||||||
* Basic matchParams used in a lot of requests
|
const query = `
|
||||||
* @param puuid of the summoner
|
SELECT
|
||||||
*/
|
SUM(match_players.kills) as kills,
|
||||||
private matchParams (puuid: string, season?: number) {
|
SUM(match_players.deaths) as deaths,
|
||||||
return {
|
SUM(match_players.assists) as assists,
|
||||||
summoner_puuid: puuid,
|
SUM(match_players.minions) as minions,
|
||||||
result: { $not: { $eq: 'Remake' } },
|
SUM(matches.game_duration) as time,
|
||||||
gamemode: { $nin: [800, 810, 820, 830, 840, 850, 2000, 2010, 2020] },
|
SUM(match_players.vision_score) as vision,
|
||||||
season: season ? season : { $exists: true },
|
COUNT(match_players.id) as count,
|
||||||
}
|
AVG(match_players.kp) as kp,
|
||||||
|
SUM(match_players.win) as wins,
|
||||||
|
SUM(match_players.loss) as losses
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
LIMIT
|
||||||
|
1
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
return rows[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async gamemodeStats(puuid: string) {
|
||||||
* Build the aggregate mongo query
|
const query = `
|
||||||
* @param puuid
|
SELECT
|
||||||
* @param matchParams
|
matches.gamemode as id,
|
||||||
* @param intermediateSteps
|
COUNT(match_players.id) as count,
|
||||||
* @param groupId
|
SUM(match_players.win) as wins,
|
||||||
* @param groupParams
|
SUM(match_players.loss) as losses
|
||||||
* @param finalSteps
|
FROM
|
||||||
*/
|
match_players
|
||||||
private async aggregate (
|
${this.JOIN_MATCHES}
|
||||||
puuid: string,
|
WHERE
|
||||||
matchParams: object,
|
${this.GLOBAL_FILTERS}
|
||||||
intermediateSteps: any[],
|
GROUP BY
|
||||||
groupId: any,
|
matches.gamemode
|
||||||
groupParams: object,
|
ORDER BY
|
||||||
finalSteps: any[],
|
count DESC
|
||||||
season?: number,
|
`
|
||||||
) {
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
return this.collection.aggregate([
|
return rows
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
...this.matchParams(puuid, season),
|
|
||||||
...matchParams,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...intermediateSteps,
|
|
||||||
{
|
|
||||||
$group: {
|
|
||||||
_id: groupId,
|
|
||||||
count: { $sum: 1 },
|
|
||||||
wins: {
|
|
||||||
$sum: {
|
|
||||||
$cond: [{ $eq: ['$result', 'Win'] }, 1, 0],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
losses: {
|
|
||||||
$sum: {
|
|
||||||
$cond: [{ $eq: ['$result', 'Fail'] }, 1, 0],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...groupParams,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...finalSteps,
|
|
||||||
]).toArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async roleStats(puuid: string) {
|
||||||
* Get MongoDB matches collection
|
const query = `
|
||||||
*/
|
SELECT
|
||||||
public async getCollection () {
|
match_players.team_position as role,
|
||||||
if (!this.collection) {
|
COUNT(match_players.id) as count,
|
||||||
this.collection = await mongodb.connection().collection('matches')
|
SUM(match_players.win) as wins,
|
||||||
}
|
SUM(match_players.loss) as losses
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
AND match_players.team_position != 0
|
||||||
|
GROUP BY
|
||||||
|
role
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async championStats(puuid: string, limit: number) {
|
||||||
* Get Summoner's statistics for the N most played champions
|
const query = `
|
||||||
* @param puuid of the summoner
|
SELECT
|
||||||
* @param limit number of champions to fetch
|
match_players.champion_id as id,
|
||||||
* @param season
|
SUM(match_players.assists) as assists,
|
||||||
*/
|
SUM(match_players.deaths) as deaths,
|
||||||
public async championStats (puuid: string, limit = 5, season?: number) {
|
SUM(match_players.kills) as kills,
|
||||||
const groupParams = {
|
COUNT(match_players.id) as count,
|
||||||
champion: { $first: '$champion' },
|
SUM(match_players.win) as wins,
|
||||||
kills: { $sum: '$stats.kills' },
|
SUM(match_players.loss) as losses
|
||||||
deaths: { $sum: '$stats.deaths' },
|
FROM
|
||||||
assists: { $sum: '$stats.assists' },
|
match_players
|
||||||
}
|
${this.JOIN_MATCHES}
|
||||||
const finalSteps = [
|
WHERE
|
||||||
{ $sort: { 'count': -1, 'champion.name': 1 } },
|
${this.GLOBAL_FILTERS}
|
||||||
{ $limit: limit },
|
GROUP BY
|
||||||
]
|
match_players.champion_id
|
||||||
return this.aggregate(puuid, {}, [], '$champion.id', groupParams, finalSteps, season)
|
ORDER BY
|
||||||
|
count DESC, match_players.champion_id
|
||||||
|
LIMIT
|
||||||
|
:limit
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid, limit })
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async championClassStats(puuid: string) {
|
||||||
* Get Summoner's statistics for all played champion classes
|
const query = `
|
||||||
* @param puuid of the summoner
|
SELECT
|
||||||
* @param season
|
match_players.champion_role as id,
|
||||||
*/
|
COUNT(match_players.id) as count,
|
||||||
public async championClassStats (puuid: string, season?: number) {
|
SUM(match_players.win) as wins,
|
||||||
const groupId = { '$arrayElemAt': ['$champion.roles', 0] }
|
SUM(match_players.loss) as losses
|
||||||
return this.aggregate(puuid, {}, [], groupId, {}, [], season)
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
GROUP BY
|
||||||
|
match_players.champion_role
|
||||||
|
ORDER BY
|
||||||
|
count DESC
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Summoner's complete statistics for the all played champs
|
|
||||||
* @param puuid of the summoner
|
|
||||||
* @param queue of the matches to fetch, if not set: get all matches
|
|
||||||
* @param season of the matches to fetch, if not set: get all seasons
|
|
||||||
*/
|
|
||||||
public async championCompleteStats(puuid: string, queue?: number, season?: number) {
|
public async championCompleteStats(puuid: string, queue?: number, season?: number) {
|
||||||
const matchParams = queue ? { gamemode: { $eq: Number(queue) } } : {}
|
const query = `
|
||||||
const groupParams = {
|
SELECT
|
||||||
time: { $sum: '$time' },
|
match_players.champion_id as id,
|
||||||
gameLength: { $avg: '$time' },
|
SUM(match_players.assists) as assists,
|
||||||
date: { $max: '$date' },
|
SUM(match_players.deaths) as deaths,
|
||||||
champion: { $first: '$champion' },
|
SUM(match_players.kills) as kills,
|
||||||
kills: { $sum: '$stats.kills' },
|
COUNT(match_players.id) as count,
|
||||||
deaths: { $sum: '$stats.deaths' },
|
SUM(match_players.win) as wins,
|
||||||
assists: { $sum: '$stats.assists' },
|
SUM(match_players.loss) as losses,
|
||||||
minions: { $avg: '$stats.minions' },
|
AVG(matches.game_duration)::int as "gameLength",
|
||||||
gold: { $avg: '$stats.gold' },
|
AVG(match_players.minions)::int as minions,
|
||||||
dmgChamp: { $avg: '$stats.dmgChamp' },
|
AVG(match_players.gold)::int as gold,
|
||||||
dmgTaken: { $avg: '$stats.dmgTaken' },
|
AVG(match_players.damage_dealt_champions)::int as "dmgChamp",
|
||||||
kp: { $avg: '$stats.kp' },
|
AVG(match_players.damage_taken)::int as "dmgTaken",
|
||||||
|
AVG(match_players.kp) as kp,
|
||||||
|
MAX(matches.date) as date
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
GROUP BY
|
||||||
|
match_players.champion_id
|
||||||
|
ORDER BY
|
||||||
|
count DESC, match_players.champion_id
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
const finalSteps = [
|
|
||||||
{ $sort: { 'count': -1, 'champion.name': 1 } },
|
public async mates(puuid: string) {
|
||||||
|
const query = `
|
||||||
|
SELECT
|
||||||
|
(array_agg(mates.summoner_name ORDER BY mates.match_id DESC))[1] as name,
|
||||||
|
COUNT(match_players.id) as count,
|
||||||
|
SUM(match_players.win) as wins,
|
||||||
|
SUM(match_players.loss) as losses
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_ALL}
|
||||||
|
INNER JOIN match_players as mates ON match_players.match_id = mates.match_id AND match_players.team = mates.team
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
GROUP BY
|
||||||
|
mates.summoner_puuid
|
||||||
|
ORDER BY
|
||||||
|
count DESC, wins DESC
|
||||||
|
LIMIT
|
||||||
|
15
|
||||||
|
`
|
||||||
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
|
|
||||||
|
// Remove the Summoner himself + unique game mates
|
||||||
|
return rows.splice(1).filter((row) => row.count > 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async records(puuid: string) {
|
||||||
|
const fields = [
|
||||||
|
'match_players.kills',
|
||||||
|
'match_players.deaths',
|
||||||
|
'match_players.assists',
|
||||||
|
'match_players.gold',
|
||||||
|
'matches.game_duration',
|
||||||
|
'match_players.minions',
|
||||||
|
'match_players.kda',
|
||||||
|
'match_players.damage_taken',
|
||||||
|
'match_players.damage_dealt_champions',
|
||||||
|
'match_players.damage_dealt_objectives',
|
||||||
|
'match_players.kp',
|
||||||
|
'match_players.vision_score',
|
||||||
|
'match_players.critical_strike',
|
||||||
|
'match_players.time_spent_living',
|
||||||
|
'match_players.heal',
|
||||||
|
'match_players.turret_kills',
|
||||||
|
'match_players.killing_spree',
|
||||||
|
'match_players.double_kills',
|
||||||
|
'match_players.triple_kills',
|
||||||
|
'match_players.quadra_kills',
|
||||||
|
'match_players.penta_kills',
|
||||||
]
|
]
|
||||||
return this.aggregate(puuid, matchParams, [], '$champion.id', groupParams, finalSteps, season)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const query = fields
|
||||||
* Get Summoner's statistics for all played modes
|
.map((field) => {
|
||||||
* @param puuid of the summoner
|
return `
|
||||||
* @param season
|
(SELECT
|
||||||
*/
|
'${field}' AS what,
|
||||||
public async gamemodeStats (puuid: string, season?: number) {
|
${field} AS amount,
|
||||||
return this.aggregate(puuid, {}, [], '$gamemode', {}, [], season)
|
match_players.win as result,
|
||||||
}
|
matches.id,
|
||||||
|
matches.date,
|
||||||
|
matches.gamemode,
|
||||||
|
match_players.champion_id
|
||||||
|
FROM
|
||||||
|
match_players
|
||||||
|
${this.JOIN_MATCHES}
|
||||||
|
WHERE
|
||||||
|
${this.GLOBAL_FILTERS}
|
||||||
|
ORDER BY
|
||||||
|
${field} DESC, matches.id
|
||||||
|
LIMIT
|
||||||
|
1)
|
||||||
|
`
|
||||||
|
})
|
||||||
|
.join('UNION ALL ')
|
||||||
|
|
||||||
/**
|
const { rows } = await Database.rawQuery(query, { puuid })
|
||||||
* Get global Summoner's statistics
|
return rows
|
||||||
* @param puuid of the summoner
|
|
||||||
* @param season
|
|
||||||
*/
|
|
||||||
public async globalStats (puuid: string, season?: number) {
|
|
||||||
const groupParams = {
|
|
||||||
time: { $sum: '$time' },
|
|
||||||
kills: { $sum: '$stats.kills' },
|
|
||||||
deaths: { $sum: '$stats.deaths' },
|
|
||||||
assists: { $sum: '$stats.assists' },
|
|
||||||
minions: { $sum: '$stats.minions' },
|
|
||||||
vision: { $sum: '$stats.vision' },
|
|
||||||
kp: { $avg: '$stats.kp' },
|
|
||||||
}
|
|
||||||
return this.aggregate(puuid, {}, [], null, groupParams, [], season)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Summoner's all records
|
|
||||||
* @param puuid of the summoner
|
|
||||||
* @param season of the matches to fetch, if null get all seasons
|
|
||||||
*/
|
|
||||||
public async records (puuid: string, season?: number) {
|
|
||||||
const records = await this.collection.aggregate([
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
...this.matchParams(puuid, season),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$group: {
|
|
||||||
_id: null,
|
|
||||||
maxKills: { $max: '$stats.kills' },
|
|
||||||
maxDeaths: { $max: '$stats.deaths' },
|
|
||||||
maxAssists: { $max: '$stats.assists' },
|
|
||||||
maxGold: { $max: '$stats.gold' },
|
|
||||||
maxTime: { $max: '$time' },
|
|
||||||
maxMinions: { $max: '$stats.minions' },
|
|
||||||
maxKda: { $max: '$stats.realKda' },
|
|
||||||
maxDmgTaken: { $max: '$stats.dmgTaken' },
|
|
||||||
maxDmgChamp: { $max: '$stats.dmgChamp' },
|
|
||||||
maxDmgObj: { $max: '$stats.dmgObj' },
|
|
||||||
maxKp: { $max: '$stats.kp' },
|
|
||||||
maxVision: { $max: '$stats.vision' },
|
|
||||||
maxCriticalStrike: { $max: '$stats.criticalStrike' },
|
|
||||||
maxLiving: { $max: '$stats.longestLiving' },
|
|
||||||
maxHeal: { $max: '$stats.heal' },
|
|
||||||
maxTowers: { $max: '$stats.towers' },
|
|
||||||
maxKillingSpree: { $max: '$stats.killingSpree' },
|
|
||||||
maxDouble: { $max: '$stats.doubleKills' },
|
|
||||||
maxTriple: { $max: '$stats.tripleKills' },
|
|
||||||
maxQuadra: { $max: '$stats.quadraKills' },
|
|
||||||
maxPenta: { $max: '$stats.pentaKills' },
|
|
||||||
docs: {
|
|
||||||
'$push': {
|
|
||||||
'champion': '$champion',
|
|
||||||
'gameId': '$gameId',
|
|
||||||
'kills': '$stats.kills',
|
|
||||||
'deaths': '$stats.deaths',
|
|
||||||
'assists': '$stats.assists',
|
|
||||||
'gold': '$stats.gold',
|
|
||||||
'time': '$time',
|
|
||||||
'minions': '$stats.minions',
|
|
||||||
'kda': '$stats.realKda',
|
|
||||||
'dmgTaken': '$stats.dmgTaken',
|
|
||||||
'dmgChamp': '$stats.dmgChamp',
|
|
||||||
'dmgObj': '$stats.dmgObj',
|
|
||||||
'kp': '$stats.kp',
|
|
||||||
'vision': '$stats.vision',
|
|
||||||
'criticalStrike': '$stats.criticalStrike',
|
|
||||||
'longestLiving': '$stats.longestLiving',
|
|
||||||
'heal': '$stats.heal',
|
|
||||||
'towers': '$stats.towers',
|
|
||||||
'killingSpree': '$stats.killingSpree',
|
|
||||||
'doubleKills': '$stats.doubleKills',
|
|
||||||
'tripleKills': '$stats.tripleKills',
|
|
||||||
'quadraKills': '$stats.quadraKills',
|
|
||||||
'pentaKills': '$stats.pentaKills',
|
|
||||||
'result': '$result',
|
|
||||||
'date': '$date',
|
|
||||||
'gamemode': '$gamemode',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
_id: 0,
|
|
||||||
/* eslint-disable max-len */
|
|
||||||
maxKills: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kills', '$maxKills'] } } }, 0] },
|
|
||||||
maxDeaths: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.deaths', '$maxDeaths'] } } }, 0] },
|
|
||||||
maxAssists: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.assists', '$maxAssists'] } } }, 0] },
|
|
||||||
maxGold: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.gold', '$maxGold'] } } }, 0] },
|
|
||||||
maxTime: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.time', '$maxTime'] } } }, 0] },
|
|
||||||
maxMinions: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.minions', '$maxMinions'] } } }, 0] },
|
|
||||||
maxKda: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kda', '$maxKda'] } } }, 0] },
|
|
||||||
maxDmgTaken: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgTaken', '$maxDmgTaken'] } } }, 0] },
|
|
||||||
maxDmgChamp: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgChamp', '$maxDmgChamp'] } } }, 0] },
|
|
||||||
maxDmgObj: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgObj', '$maxDmgObj'] } } }, 0] },
|
|
||||||
maxKp: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kp', '$maxKp'] } } }, 0] },
|
|
||||||
maxVision: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.vision', '$maxVision'] } } }, 0] },
|
|
||||||
maxCriticalStrike: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.criticalStrike', '$maxCriticalStrike'] } } }, 0] },
|
|
||||||
maxLiving: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.longestLiving', '$maxLiving'] } } }, 0] },
|
|
||||||
maxHeal: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.heal', '$maxHeal'] } } }, 0] },
|
|
||||||
maxTowers: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.towers', '$maxTowers'] } } }, 0] },
|
|
||||||
maxKillingSpree: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.killingSpree', '$maxKillingSpree'] } } }, 0] },
|
|
||||||
maxDouble: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.doubleKills', '$maxDouble'] } } }, 0] },
|
|
||||||
maxTriple: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.tripleKills', '$maxTriple'] } } }, 0] },
|
|
||||||
maxQuadra: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.quadraKills', '$maxQuadra'] } } }, 0] },
|
|
||||||
maxPenta: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.pentaKills', '$maxPenta'] } } }, 0] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]).toArray()
|
|
||||||
|
|
||||||
return records[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Summoner's statistics for the 5 differnt roles
|
|
||||||
* @param puuid of the summoner
|
|
||||||
* @param season
|
|
||||||
*/
|
|
||||||
public async roleStats (puuid: string, season?: number) {
|
|
||||||
const matchParams = {
|
|
||||||
role: { $not: { $eq: 'NONE' } },
|
|
||||||
}
|
|
||||||
const finalSteps = [
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
role: '$_id',
|
|
||||||
count: '$count',
|
|
||||||
wins: '$wins',
|
|
||||||
losses: '$losses',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
return this.aggregate(puuid, matchParams, [], '$role', {}, finalSteps, season)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Summoner's played seasons
|
|
||||||
* @param puuid of the summoner
|
|
||||||
*/
|
|
||||||
public async seasons (puuid: string) {
|
|
||||||
return this.collection.aggregate([
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
...this.matchParams(puuid),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$group: { _id: '$season' },
|
|
||||||
},
|
|
||||||
]).toArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Summoner's mates list
|
|
||||||
* @param puuid of the summoner
|
|
||||||
* @param season
|
|
||||||
*/
|
|
||||||
public async mates (puuid: string, season?: number) {
|
|
||||||
const intermediateSteps = [
|
|
||||||
{ $sort: { 'gameId': -1 } },
|
|
||||||
{ $unwind: '$allyTeam' },
|
|
||||||
]
|
|
||||||
const groupParams = {
|
|
||||||
account_id: { $first: '$account_id' },
|
|
||||||
name: { $first: '$allyTeam.name' },
|
|
||||||
mateId: { $first: '$allyTeam.account_id' },
|
|
||||||
}
|
|
||||||
const finalSteps = [
|
|
||||||
{
|
|
||||||
'$addFields': {
|
|
||||||
'idEq': { '$eq': ['$mateId', '$account_id'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
'idEq': false,
|
|
||||||
'count': { $gte: 2 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ $sort: { 'count': -1, 'name': 1 } },
|
|
||||||
{ $limit: 15 },
|
|
||||||
]
|
|
||||||
return this.aggregate(puuid, {}, intermediateSteps, '$allyTeam.account_id', groupParams, finalSteps, season)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import Env from '@ioc:Adonis/Core/Env'
|
import Env from '@ioc:Adonis/Core/Env'
|
||||||
|
|
||||||
export interface JaxConfig {
|
export interface JaxConfig {
|
||||||
key: string,
|
key: string
|
||||||
region: string,
|
region: string
|
||||||
requestOptions: JaxConfigRequestOptions
|
requestOptions: JaxConfigRequestOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JaxConfigRequestOptions {
|
export interface JaxConfigRequestOptions {
|
||||||
retriesBeforeAbort: number,
|
retriesBeforeAbort: number
|
||||||
delayBeforeRetry: number,
|
delayBeforeRetry: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const JAX_CONFIG: JaxConfig = {
|
export const JAX_CONFIG: JaxConfig = {
|
||||||
key: Env.get('API_KEY') as string,
|
key: Env.get('RIOT_API_KEY') as string,
|
||||||
region: 'euw1',
|
region: 'euw1',
|
||||||
requestOptions: {
|
requestOptions: {
|
||||||
retriesBeforeAbort: 3,
|
retriesBeforeAbort: 3,
|
||||||
|
|
|
||||||
|
|
@ -2,76 +2,76 @@ import { JaxConfig } from '../../JaxConfig'
|
||||||
import CDragonRequest from '../CDragonRequest'
|
import CDragonRequest from '../CDragonRequest'
|
||||||
|
|
||||||
export interface ChampionDTO {
|
export interface ChampionDTO {
|
||||||
id: number,
|
id: number
|
||||||
name: string,
|
name: string
|
||||||
alias: string,
|
alias: string
|
||||||
squarePortraitPath: string,
|
squarePortraitPath: string
|
||||||
roles: string[]
|
roles: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemDTO {
|
export interface ItemDTO {
|
||||||
id: number,
|
id: number
|
||||||
name: string,
|
name: string
|
||||||
description: string,
|
description: string
|
||||||
active: boolean,
|
active: boolean
|
||||||
inStore: boolean,
|
inStore: boolean
|
||||||
from: number[],
|
from: number[]
|
||||||
to: number[],
|
to: number[]
|
||||||
categories: string[],
|
categories: string[]
|
||||||
mapStringIdInclusions: string[],
|
mapStringIdInclusions: string[]
|
||||||
maxStacks: number,
|
maxStacks: number
|
||||||
modeNameInclusions: string[],
|
modeNameInclusions: string[]
|
||||||
requiredChampion: string,
|
requiredChampion: string
|
||||||
requiredAlly: string,
|
requiredAlly: string
|
||||||
requiredBuffCurrencyName: string,
|
requiredBuffCurrencyName: string
|
||||||
requiredBuffCurrencyCost: number,
|
requiredBuffCurrencyCost: number
|
||||||
specialRecipe: number,
|
specialRecipe: number
|
||||||
isEnchantment: boolean,
|
isEnchantment: boolean
|
||||||
price: number,
|
price: number
|
||||||
priceTotal: number,
|
priceTotal: number
|
||||||
iconPath: string
|
iconPath: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkDTO {
|
export interface PerkDTO {
|
||||||
id: number,
|
id: number
|
||||||
name: string,
|
name: string
|
||||||
majorChangePatchVersion: string,
|
majorChangePatchVersion: string
|
||||||
tooltip: string,
|
tooltip: string
|
||||||
shortDesc: string,
|
shortDesc: string
|
||||||
longDesc: string,
|
longDesc: string
|
||||||
iconPath: string,
|
iconPath: string
|
||||||
endOfGameStatDescs: string[]
|
endOfGameStatDescs: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkStyleResponse {
|
export interface PerkStyleResponse {
|
||||||
schemaVersion: string,
|
schemaVersion: string
|
||||||
styles: PerkStyleDTO[]
|
styles: PerkStyleDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkStyleDTO {
|
export interface PerkStyleDTO {
|
||||||
id: number,
|
id: number
|
||||||
name: string,
|
name: string
|
||||||
tooltip: string,
|
tooltip: string
|
||||||
iconPath: string,
|
iconPath: string
|
||||||
assetMap: { [key: string]: string },
|
assetMap: { [key: string]: string }
|
||||||
isAdvanced: boolean,
|
isAdvanced: boolean
|
||||||
allowedSubStyles: number[],
|
allowedSubStyles: number[]
|
||||||
subStyleBonus: { styleId: number, perkId: number }[],
|
subStyleBonus: { styleId: number; perkId: number }[]
|
||||||
slots: { type: string, slotLabel: string, perks: number[] }[],
|
slots: { type: string; slotLabel: string; perks: number[] }[]
|
||||||
defaultPageName: string,
|
defaultPageName: string
|
||||||
defaultSubStyle: number,
|
defaultSubStyle: number
|
||||||
defaultPerks: number[],
|
defaultPerks: number[]
|
||||||
defaultPerksWhenSplashed: number[],
|
defaultPerksWhenSplashed: number[]
|
||||||
defaultStatModsPerSubStyle: { id: string, perks: number[] }[]
|
defaultStatModsPerSubStyle: { id: string; perks: number[] }[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SummonerSpellDTO {
|
export interface SummonerSpellDTO {
|
||||||
id: number,
|
id: number
|
||||||
name: string,
|
name: string
|
||||||
description: string,
|
description: string
|
||||||
summonerLevel: number,
|
summonerLevel: number
|
||||||
cooldown: number,
|
cooldown: number
|
||||||
gameModes: string[],
|
gameModes: string[]
|
||||||
iconPath: string
|
iconPath: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,26 @@ import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
import JaxRequest from '../JaxRequest'
|
||||||
|
|
||||||
export interface LeagueEntryDTO {
|
export interface LeagueEntryDTO {
|
||||||
leagueId: string;
|
leagueId: string
|
||||||
queueType: string;
|
queueType: string
|
||||||
tier: string;
|
tier: string
|
||||||
rank: string;
|
rank: string
|
||||||
summonerId: string;
|
summonerId: string
|
||||||
summonerName: string;
|
summonerName: string
|
||||||
leaguePoints: number;
|
leaguePoints: number
|
||||||
wins: number;
|
wins: number
|
||||||
losses: number;
|
losses: number
|
||||||
veteran: boolean;
|
veteran: boolean
|
||||||
inactive: boolean;
|
inactive: boolean
|
||||||
freshBlood: boolean;
|
freshBlood: boolean
|
||||||
hotStreak: boolean;
|
hotStreak: boolean
|
||||||
miniSeries?: MiniSeriesDTO
|
miniSeries?: MiniSeriesDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MiniSeriesDTO {
|
interface MiniSeriesDTO {
|
||||||
losses: number,
|
losses: number
|
||||||
progress: string,
|
progress: string
|
||||||
target: number,
|
target: number
|
||||||
wins: number
|
wins: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,380 +4,165 @@ import RiotRateLimiter from 'riot-ratelimiter'
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
import JaxRequest from '../JaxRequest'
|
||||||
|
|
||||||
// export interface MatchDto {
|
|
||||||
// gameId: number,
|
|
||||||
// participantIdentities: ParticipantIdentityDto[],
|
|
||||||
// queueId: number,
|
|
||||||
// gameType: string,
|
|
||||||
// gameDuration: number,
|
|
||||||
// teams: TeamStatsDto[],
|
|
||||||
// platformId: string
|
|
||||||
// gameCreation: number,
|
|
||||||
// seasonId: number,
|
|
||||||
// gameVersion: string,
|
|
||||||
// mapId: number,
|
|
||||||
// gameMode: string,
|
|
||||||
// participants: ParticipantDto[],
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ParticipantIdentityDto {
|
|
||||||
// participantId: number,
|
|
||||||
// player: PlayerDto
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface PlayerDto {
|
|
||||||
// profileIcon: number,
|
|
||||||
// accountId: string,
|
|
||||||
// matchHistoryUri: string,
|
|
||||||
// currentAccountId: string,
|
|
||||||
// currentPlatformId: string,
|
|
||||||
// summonerName: string,
|
|
||||||
// summonerId: string,
|
|
||||||
// platformId: string,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface TeamStatsDto {
|
|
||||||
// towerKills: number,
|
|
||||||
// riftHeraldKills: number,
|
|
||||||
// firstBlood: boolean,
|
|
||||||
// inhibitorKills: number,
|
|
||||||
// bans: TeamBansDto[],
|
|
||||||
// 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 TeamBansDto {
|
|
||||||
// championId: number,
|
|
||||||
// pickTurn: number,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ParticipantDto {
|
|
||||||
// participantId: number,
|
|
||||||
// championId: number,
|
|
||||||
// runes: RuneDto[],
|
|
||||||
// stats: ParticipantStatsDto,
|
|
||||||
// teamId: number,
|
|
||||||
// timeline: ParticipantTimelineDto,
|
|
||||||
// spell1Id: number,
|
|
||||||
// spell2Id: number,
|
|
||||||
// highestAchievedSeasonTier?:
|
|
||||||
// 'CHALLENGER' | 'MASTER' | 'DIAMOND' | 'PLATINUM' | 'GOLD' | 'SILVER' | 'BRONZE' | 'UNRANKED',
|
|
||||||
// masteries: MasteryDto[]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface RuneDto {
|
|
||||||
// runeId: number,
|
|
||||||
// rank: number,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ParticipantStatsDto {
|
|
||||||
// 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 ParticipantTimelineDto {
|
|
||||||
// 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 MasteryDto {
|
|
||||||
// rank: number,
|
|
||||||
// masteryId: number,
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* ===============================================
|
|
||||||
* V5
|
|
||||||
* ===============================================
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface MatchDto {
|
export interface MatchDto {
|
||||||
metadata: MetadataDto;
|
metadata: MetadataDto
|
||||||
info: InfoDto;
|
info: InfoDto
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataDto {
|
export interface MetadataDto {
|
||||||
dataVersion: string;
|
dataVersion: string
|
||||||
matchId: string;
|
matchId: string
|
||||||
participants: string[];
|
participants: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfoDto {
|
export interface InfoDto {
|
||||||
gameCreation: number;
|
gameCreation: number
|
||||||
gameDuration: number;
|
gameDuration: number
|
||||||
gameId: number;
|
gameId: number
|
||||||
gameMode: string;
|
gameMode: string
|
||||||
gameName: string;
|
gameName: string
|
||||||
gameStartTimestamp: number;
|
gameStartTimestamp: number
|
||||||
gameType: string;
|
gameType: string
|
||||||
gameVersion: string;
|
gameVersion: string
|
||||||
mapId: number;
|
mapId: number
|
||||||
participants: ParticipantDto[];
|
participants: ParticipantDto[]
|
||||||
platformId: string;
|
platformId: string
|
||||||
queueId: number;
|
queueId: number
|
||||||
teams: TeamDto[];
|
teams: TeamDto[]
|
||||||
tournamentCode?: string;
|
tournamentCode?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParticipantDto {
|
export interface ParticipantDto {
|
||||||
assists: number;
|
assists: number
|
||||||
baronKills: number;
|
baronKills: number
|
||||||
bountyLevel: number;
|
bountyLevel: number
|
||||||
champExperience: number;
|
champExperience: number
|
||||||
champLevel: number;
|
champLevel: number
|
||||||
championId: number;
|
championId: number
|
||||||
championName: string;
|
championName: string
|
||||||
championTransform: ChampionTransformDto;
|
championTransform: ChampionTransformDto
|
||||||
consumablesPurchased: number;
|
consumablesPurchased: number
|
||||||
damageDealtToObjectives: number;
|
damageDealtToObjectives: number
|
||||||
damageDealtToTurrets: number;
|
damageDealtToTurrets: number
|
||||||
damageSelfMitigated: number;
|
damageSelfMitigated: number
|
||||||
deaths: number;
|
deaths: number
|
||||||
detectorWardsPlaced: number;
|
detectorWardsPlaced: number
|
||||||
doubleKills: number;
|
doubleKills: number
|
||||||
dragonKills: number;
|
dragonKills: number
|
||||||
firstBloodAssist: boolean;
|
firstBloodAssist: boolean
|
||||||
firstBloodKill: boolean;
|
firstBloodKill: boolean
|
||||||
firstTowerAssist: boolean;
|
firstTowerAssist: boolean
|
||||||
firstTowerKill: boolean;
|
firstTowerKill: boolean
|
||||||
gameEndedInEarlySurrender: boolean;
|
gameEndedInEarlySurrender: boolean
|
||||||
gameEndedInSurrender: boolean;
|
gameEndedInSurrender: boolean
|
||||||
goldEarned: number;
|
goldEarned: number
|
||||||
goldSpent: number;
|
goldSpent: number
|
||||||
individualPosition: 'Invalid' | TeamPositionDto; // TODO
|
individualPosition: 'Invalid' | TeamPositionDto // TODO
|
||||||
inhibitorKills: number;
|
inhibitorKills: number
|
||||||
item0: number;
|
item0: number
|
||||||
item1: number;
|
item1: number
|
||||||
item2: number;
|
item2: number
|
||||||
item3: number;
|
item3: number
|
||||||
item4: number;
|
item4: number
|
||||||
item5: number;
|
item5: number
|
||||||
item6: number;
|
item6: number
|
||||||
itemsPurchased: number;
|
itemsPurchased: number
|
||||||
killingSprees: number;
|
killingSprees: number
|
||||||
kills: number;
|
kills: number
|
||||||
lane: LaneDto; // TODO
|
lane: LaneDto // TODO
|
||||||
largestCriticalStrike: number;
|
largestCriticalStrike: number
|
||||||
largestKillingSpree: number;
|
largestKillingSpree: number
|
||||||
largestMultiKill: number;
|
largestMultiKill: number
|
||||||
longestTimeSpentLiving: number;
|
longestTimeSpentLiving: number
|
||||||
magicDamageDealt: number;
|
magicDamageDealt: number
|
||||||
magicDamageDealtToChampions: number;
|
magicDamageDealtToChampions: number
|
||||||
magicDamageTaken: number;
|
magicDamageTaken: number
|
||||||
neutralMinionsKilled: number;
|
neutralMinionsKilled: number
|
||||||
nexusKills: number;
|
nexusKills: number
|
||||||
objectivesStolen: number;
|
objectivesStolen: number
|
||||||
objectivesStolenAssists: number;
|
objectivesStolenAssists: number
|
||||||
participantId: number;
|
participantId: number
|
||||||
pentaKills: number;
|
pentaKills: number
|
||||||
perks: PerksDto;
|
perks: PerksDto
|
||||||
physicalDamageDealt: number;
|
physicalDamageDealt: number
|
||||||
physicalDamageDealtToChampions: number;
|
physicalDamageDealtToChampions: number
|
||||||
physicalDamageTaken: number;
|
physicalDamageTaken: number
|
||||||
profileIcon: number;
|
profileIcon: number
|
||||||
puuid: string;
|
puuid: string
|
||||||
quadraKills: number;
|
quadraKills: number
|
||||||
riotIdName: string;
|
riotIdName: string
|
||||||
riotIdTagline: string;
|
riotIdTagline: string
|
||||||
role: RoleDto; // TODO
|
role: RoleDto // TODO
|
||||||
sightWardsBoughtInGame: number;
|
sightWardsBoughtInGame: number
|
||||||
spell1Casts: number;
|
spell1Casts: number
|
||||||
spell2Casts: number;
|
spell2Casts: number
|
||||||
spell3Casts: number;
|
spell3Casts: number
|
||||||
spell4Casts: number;
|
spell4Casts: number
|
||||||
summoner1Casts: number;
|
summoner1Casts: number
|
||||||
summoner1Id: number;
|
summoner1Id: number
|
||||||
summoner2Casts: number;
|
summoner2Casts: number
|
||||||
summoner2Id: number;
|
summoner2Id: number
|
||||||
summonerId: string;
|
summonerId: string
|
||||||
summonerLevel: number;
|
summonerLevel: number
|
||||||
summonerName: string;
|
summonerName: string
|
||||||
teamEarlySurrendered: boolean;
|
teamEarlySurrendered: boolean
|
||||||
teamId: number;
|
teamId: number
|
||||||
teamPosition: TeamPositionDto; // TODO
|
teamPosition: TeamPositionDto // TODO
|
||||||
timeCCingOthers: number;
|
timeCCingOthers: number
|
||||||
timePlayed: number;
|
timePlayed: number
|
||||||
totalDamageDealt: number;
|
totalDamageDealt: number
|
||||||
totalDamageDealtToChampions: number;
|
totalDamageDealtToChampions: number
|
||||||
totalDamageShieldedOnTeammates: number;
|
totalDamageShieldedOnTeammates: number
|
||||||
totalDamageTaken: number;
|
totalDamageTaken: number
|
||||||
totalHeal: number;
|
totalHeal: number
|
||||||
totalHealsOnTeammates: number;
|
totalHealsOnTeammates: number
|
||||||
totalMinionsKilled: number;
|
totalMinionsKilled: number
|
||||||
totalTimeCCDealt: number;
|
totalTimeCCDealt: number
|
||||||
totalTimeSpentDead: number;
|
totalTimeSpentDead: number
|
||||||
totalUnitsHealed: number;
|
totalUnitsHealed: number
|
||||||
tripleKills: number;
|
tripleKills: number
|
||||||
trueDamageDealt: number;
|
trueDamageDealt: number
|
||||||
trueDamageDealtToChampions: number;
|
trueDamageDealtToChampions: number
|
||||||
trueDamageTaken: number;
|
trueDamageTaken: number
|
||||||
turretKills: number;
|
turretKills: number
|
||||||
unrealKills: number;
|
unrealKills: number
|
||||||
visionScore: number;
|
visionScore: number
|
||||||
visionWardsBoughtInGame: number;
|
visionWardsBoughtInGame: number
|
||||||
wardsKilled: number;
|
wardsKilled: number
|
||||||
wardsPlaced: number;
|
wardsPlaced: number
|
||||||
win: boolean;
|
win: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChampionTransformDto {
|
export enum ChampionTransformDto {
|
||||||
None,
|
None,
|
||||||
Slayer,
|
Slayer,
|
||||||
Assasin
|
Assasin,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LaneDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM'
|
export type LaneDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM'
|
||||||
|
|
||||||
export interface PerksDto {
|
export interface PerksDto {
|
||||||
statPerks: PerkStatsDto;
|
statPerks: PerkStatsDto
|
||||||
styles: PerkStyleDto[];
|
styles: PerkStyleDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkStatsDto {
|
export interface PerkStatsDto {
|
||||||
defense: number;
|
defense: number
|
||||||
flex: number;
|
flex: number
|
||||||
offense: number;
|
offense: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkStyleDto {
|
export interface PerkStyleDto {
|
||||||
description: 'primaryStyle' | 'subStyle';
|
description: 'primaryStyle' | 'subStyle'
|
||||||
selections: PerkStyleSelectionDto[];
|
selections: PerkStyleSelectionDto[]
|
||||||
style: number;
|
style: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PerkStyleSelectionDto {
|
export interface PerkStyleSelectionDto {
|
||||||
perk: number;
|
perk: number
|
||||||
var1: number;
|
var1: number
|
||||||
var2: number;
|
var2: number
|
||||||
var3: number;
|
var3: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RoleDto = 'NONE' | 'DUO' | 'SOLO' | 'CARRY' | 'SUPPORT'
|
export type RoleDto = 'NONE' | 'DUO' | 'SOLO' | 'CARRY' | 'SUPPORT'
|
||||||
|
|
@ -385,29 +170,29 @@ export type RoleDto = 'NONE' | 'DUO' |'SOLO' | 'CARRY' | 'SUPPORT'
|
||||||
export type TeamPositionDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM' | 'UTILITY'
|
export type TeamPositionDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM' | 'UTILITY'
|
||||||
|
|
||||||
export interface TeamDto {
|
export interface TeamDto {
|
||||||
bans: BanDto[];
|
bans: BanDto[]
|
||||||
objectives: ObjectivesDto;
|
objectives: ObjectivesDto
|
||||||
teamId: number;
|
teamId: number
|
||||||
win: boolean;
|
win: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BanDto {
|
export interface BanDto {
|
||||||
championId: number;
|
championId: number
|
||||||
pickTurn: number;
|
pickTurn: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ObjectivesDto {
|
export interface ObjectivesDto {
|
||||||
baron: ObjectiveDto;
|
baron: ObjectiveDto
|
||||||
champion: ObjectiveDto;
|
champion: ObjectiveDto
|
||||||
dragon: ObjectiveDto;
|
dragon: ObjectiveDto
|
||||||
inhibitor: ObjectiveDto;
|
inhibitor: ObjectiveDto
|
||||||
riftHerald: ObjectiveDto;
|
riftHerald: ObjectiveDto
|
||||||
tower: ObjectiveDto;
|
tower: ObjectiveDto
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ObjectiveDto {
|
export interface ObjectiveDto {
|
||||||
first: boolean;
|
first: boolean
|
||||||
kills: number;
|
kills: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class MatchEndpoint {
|
export default class MatchEndpoint {
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,53 @@
|
||||||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
||||||
import RiotRateLimiter from 'riot-ratelimiter'
|
import RiotRateLimiter from 'riot-ratelimiter'
|
||||||
import { LeagueEntriesByQueue } from 'App/Services/SummonerService'
|
|
||||||
import { JaxConfig } from '../../JaxConfig'
|
import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
import JaxRequest from '../JaxRequest'
|
||||||
|
|
||||||
export interface CurrentGameInfo {
|
export interface CurrentGameInfoDTO {
|
||||||
gameId: number,
|
gameId: number
|
||||||
gameType: string
|
gameType: string
|
||||||
gameStartTime: number,
|
gameStartTime: number
|
||||||
mapId: number,
|
mapId: number
|
||||||
gameLength: number,
|
gameLength: number
|
||||||
platformId: string,
|
platformId: string
|
||||||
gameMode: string,
|
gameMode: string
|
||||||
bannedChampions: BannedChampion[],
|
bannedChampions: BannedChampionDTO[]
|
||||||
gameQueueConfigId: number,
|
gameQueueConfigId: number
|
||||||
observers: Observer,
|
observers: ObserverDTO
|
||||||
participants: CurrentGameParticipant[],
|
participants: CurrentGameParticipantDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BannedChampion {
|
export interface BannedChampionDTO {
|
||||||
pickTurn: number,
|
pickTurn: number
|
||||||
championId: number,
|
championId: number
|
||||||
teamId: number,
|
teamId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Observer {
|
export interface ObserverDTO {
|
||||||
encryptionKey: string,
|
encryptionKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CurrentGameParticipant {
|
export interface CurrentGameParticipantDTO {
|
||||||
championId: number,
|
championId: number
|
||||||
perks: Perks,
|
perks: PerksDTO
|
||||||
profileIconId: number,
|
profileIconId: number
|
||||||
bot: boolean,
|
bot: boolean
|
||||||
teamId: number,
|
teamId: number
|
||||||
summonerName: string,
|
summonerName: string
|
||||||
summonerId: string,
|
summonerId: string
|
||||||
spell1Id: number,
|
spell1Id: number
|
||||||
spell2Id: number,
|
spell2Id: number
|
||||||
gameCustomizationObjects: GameCustomizationObject[],
|
gameCustomizationObjects: GameCustomizationObjectDTO[]
|
||||||
// Custom types from here
|
|
||||||
role?: string,
|
|
||||||
runes?: { primaryRune: string, secondaryRune: string } | {}
|
|
||||||
level?: number,
|
|
||||||
rank?: LeagueEntriesByQueue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Perks {
|
export interface PerksDTO {
|
||||||
perkIds: number[]
|
perkIds: number[]
|
||||||
perkStyle: number,
|
perkStyle: number
|
||||||
perkSubStyle: number
|
perkSubStyle: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GameCustomizationObject {
|
export interface GameCustomizationObjectDTO {
|
||||||
category: string,
|
category: string
|
||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +60,7 @@ export default class SpectatorEndpoint {
|
||||||
this.limiter = limiter
|
this.limiter = limiter
|
||||||
}
|
}
|
||||||
|
|
||||||
public summonerID (summonerID: string, region: string) {
|
public summonerID(summonerID: string, region: string): Promise<CurrentGameInfoDTO | undefined> {
|
||||||
return new JaxRequest(
|
return new JaxRequest(
|
||||||
region,
|
region,
|
||||||
this.config,
|
this.config,
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,13 @@ import { JaxConfig } from '../../JaxConfig'
|
||||||
import JaxRequest from '../JaxRequest'
|
import JaxRequest from '../JaxRequest'
|
||||||
|
|
||||||
export interface SummonerDTO {
|
export interface SummonerDTO {
|
||||||
accountId: string,
|
accountId: string
|
||||||
profileIconId: number,
|
profileIconId: number
|
||||||
revisionDate: number,
|
revisionDate: number
|
||||||
name: string,
|
name: string
|
||||||
id: string,
|
id: string
|
||||||
puuid: string,
|
puuid: string
|
||||||
summonerLevel: number,
|
summonerLevel: number
|
||||||
region?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class SummonerEndpoint {
|
export default class SummonerEndpoint {
|
||||||
|
|
@ -23,6 +22,16 @@ 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> {
|
public summonerId(summonerId: string, region: string): Promise<SummonerDTO> {
|
||||||
return new JaxRequest(
|
return new JaxRequest(
|
||||||
region,
|
region,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import { JaxConfig } from '../JaxConfig'
|
||||||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
||||||
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
|
||||||
|
|
@ -15,7 +17,9 @@ export default class Jax {
|
||||||
public config: JaxConfig
|
public config: JaxConfig
|
||||||
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
|
||||||
|
|
@ -34,7 +38,9 @@ export default class Jax {
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,13 @@ export default class JaxRequest {
|
||||||
private retries: number
|
private retries: number
|
||||||
private sleep: { (ms: number): Promise<void>; <T>(ms: number, value: T): Promise<T> }
|
private sleep: { (ms: number): Promise<void>; <T>(ms: number, value: T): Promise<T> }
|
||||||
|
|
||||||
constructor (region: string, config: JaxConfig, endpoint: string, limiter: RiotRateLimiter, cacheTime: number) {
|
constructor(
|
||||||
|
region: string,
|
||||||
|
config: JaxConfig,
|
||||||
|
endpoint: string,
|
||||||
|
limiter: RiotRateLimiter,
|
||||||
|
cacheTime: number
|
||||||
|
) {
|
||||||
this.region = region
|
this.region = region
|
||||||
this.config = config
|
this.config = config
|
||||||
this.endpoint = endpoint
|
this.endpoint = endpoint
|
||||||
|
|
@ -50,14 +56,25 @@ export default class JaxRequest {
|
||||||
} catch ({ statusCode, ...rest }) {
|
} catch ({ statusCode, ...rest }) {
|
||||||
this.retries--
|
this.retries--
|
||||||
|
|
||||||
if (statusCode !== 500 && statusCode !== 503 && statusCode !== 504) { //
|
console.log('JAX ERROR')
|
||||||
|
console.log(rest?.cause?.code)
|
||||||
|
|
||||||
|
if (
|
||||||
|
statusCode !== 500 &&
|
||||||
|
statusCode !== 503 &&
|
||||||
|
statusCode !== 504 &&
|
||||||
|
rest?.cause?.code !== 'ETIMEDOUT'
|
||||||
|
) {
|
||||||
|
//
|
||||||
// Don't log 404 when summoner isn't playing or the summoner doesn't exist
|
// Don't log 404 when summoner isn't playing or the summoner doesn't exist
|
||||||
// Or if summoner has no MatchList
|
// Or if summoner has no MatchList
|
||||||
if (!this.endpoint.includes('spectator/v4/active-games/by-summoner') &&
|
if (
|
||||||
|
!this.endpoint.includes('spectator/v4/active-games/by-summoner') &&
|
||||||
!this.endpoint.includes('summoner/v4/summoners/by-name') &&
|
!this.endpoint.includes('summoner/v4/summoners/by-name') &&
|
||||||
!this.endpoint.includes('match/v4/matchlists/by-account')
|
!this.endpoint.includes('match/v4/matchlists/by-account')
|
||||||
) {
|
) {
|
||||||
Logger.error(`JaxRequest Error ${statusCode}: `, rest)
|
Logger.error(`URL ${url}: `)
|
||||||
|
// Logger.error(`JaxRequest Error ${statusCode}: `, rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,142 +1,138 @@
|
||||||
import Jax from './Jax'
|
import Jax from './Jax'
|
||||||
import Logger from '@ioc:Adonis/Core/Logger'
|
|
||||||
import { MatchlistDto } from './Jax/src/Endpoints/MatchlistEndpoint'
|
import { MatchlistDto } from './Jax/src/Endpoints/MatchlistEndpoint'
|
||||||
import { SummonerDTO } from './Jax/src/Endpoints/SummonerEndpoint'
|
import { SummonerDTO } from './Jax/src/Endpoints/SummonerEndpoint'
|
||||||
import { SummonerModel } from 'App/Models/Summoner'
|
import Summoner from 'App/Models/Summoner'
|
||||||
import Match, { MatchModel } from 'App/Models/Match'
|
import Database from '@ioc:Adonis/Lucid/Database'
|
||||||
import BasicMatchTransformer from 'App/Transformers/BasicMatchTransformer'
|
import MatchParser from 'App/Parsers/MatchParser'
|
||||||
|
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
|
||||||
|
import { SerializedMatch } from 'App/Serializers/SerializedTypes'
|
||||||
|
import Match from 'App/Models/Match'
|
||||||
|
import { notEmpty, tutorialQueues } from 'App/helpers'
|
||||||
|
|
||||||
class MatchService {
|
class MatchService {
|
||||||
/**
|
/**
|
||||||
* Add 100 matches at a time to MatchList until the stopFetching condition is true
|
* Add 100 matches at a time to MatchList until the stopFetching condition is true
|
||||||
* @param account of the summoner
|
* @param account of the summoner
|
||||||
|
* @param region of the summoner
|
||||||
* @param stopFetching condition to stop fetching the MatchList
|
* @param stopFetching condition to stop fetching the MatchList
|
||||||
*/
|
*/
|
||||||
private async _fetchMatchListUntil (account: SummonerDTO, stopFetching: any) {
|
private async _fetchMatchListUntil(account: SummonerDTO, region: string, stopFetching: any) {
|
||||||
let matchList: MatchlistDto = []
|
let matchList: MatchlistDto = []
|
||||||
let alreadyIn = false
|
let alreadyIn = false
|
||||||
let index = 0
|
let index = 0
|
||||||
do {
|
do {
|
||||||
let newMatchList = await Jax.Matchlist.puuid(account.puuid, account.region as string, index)
|
const newMatchList = await Jax.Matchlist.puuid(account.puuid, region, index)
|
||||||
// Error while fetching Riot API
|
// Error while fetching Riot API
|
||||||
if (!newMatchList) {
|
if (!newMatchList) {
|
||||||
// matchList = matchList.map(m => {
|
|
||||||
// m.season = getSeasonNumber(m.timestamp)
|
|
||||||
// return m
|
|
||||||
// })
|
|
||||||
return matchList
|
return matchList
|
||||||
}
|
}
|
||||||
matchList = [...matchList, ...newMatchList]
|
matchList = [...matchList, ...newMatchList]
|
||||||
alreadyIn = newMatchList.length === 0 || stopFetching(newMatchList)
|
alreadyIn = newMatchList.length === 0 || stopFetching(newMatchList)
|
||||||
// If the match is made in another region : we stop fetching
|
// If the match is made in another region : we stop fetching
|
||||||
// if (matchList[matchList.length - 1].platformId.toLowerCase() !== account.region) { // TODO: check if region has changed
|
if (matchList[matchList.length - 1].split('_')[0].toLowerCase() !== region.toLowerCase()) {
|
||||||
// alreadyIn = true
|
alreadyIn = true
|
||||||
// }
|
}
|
||||||
index += 100
|
index += 100
|
||||||
} while (!alreadyIn)
|
} 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
|
return matchList
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update the full MatchList of the summoner (min. 4 months)
|
* Update the full MatchList of the summoner
|
||||||
* @param account of the summoner
|
|
||||||
* @param summonerDB summoner in the database
|
|
||||||
*/
|
*/
|
||||||
public async updateMatchList (account: SummonerDTO, summonerDB: SummonerModel) {
|
public async updateMatchList(
|
||||||
|
account: SummonerDTO,
|
||||||
|
region: string,
|
||||||
|
summonerDB: Summoner
|
||||||
|
): Promise<MatchlistDto> {
|
||||||
console.time('matchList')
|
console.time('matchList')
|
||||||
|
|
||||||
// Summoner has already been searched : we already have a MatchList and we need to update it
|
const currentMatchList = await summonerDB.related('matchList').query().orderBy('matchId', 'asc')
|
||||||
if (summonerDB.matchList) {
|
const currentMatchListIds = currentMatchList.map((m) => m.matchId)
|
||||||
// Get MatchList
|
|
||||||
const matchList = await this._fetchMatchListUntil(account, (newMatchList: MatchlistDto) => {
|
const newMatchList = await this._fetchMatchListUntil(
|
||||||
return summonerDB.matchList!.some(m => m === newMatchList[newMatchList.length - 1])
|
account,
|
||||||
})
|
region,
|
||||||
// Update Summoner's MatchList
|
(newMatchList: MatchlistDto) => {
|
||||||
for (const match of matchList.reverse()) {
|
return currentMatchListIds.some((id) => id === newMatchList[newMatchList.length - 1])
|
||||||
if (!summonerDB.matchList.some(m => m === match)) {
|
}
|
||||||
summonerDB.matchList.unshift(match)
|
)
|
||||||
|
|
||||||
|
const matchListToSave: MatchlistDto = []
|
||||||
|
for (const matchId of newMatchList.reverse()) {
|
||||||
|
if (!currentMatchListIds.some((id) => id === matchId)) {
|
||||||
|
matchListToSave.push(matchId)
|
||||||
|
currentMatchListIds.push(matchId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // First search of the Summoner
|
|
||||||
// const today = Date.now()
|
// If there is new matchIds to save in database
|
||||||
// Get MatchList
|
if (matchListToSave.length) {
|
||||||
const matchList = await this._fetchMatchListUntil(account, (newMatchList: MatchlistDto) => {
|
await Database.table('summoner_matchlist').multiInsert(
|
||||||
// return (newMatchList.length !== 100 || today - newMatchList[newMatchList.length - 1].timestamp > 10368000000)
|
matchListToSave.map((id) => ({
|
||||||
return newMatchList.length === 0 // TODO: useless
|
match_id: id,
|
||||||
})
|
summoner_puuid: summonerDB.puuid,
|
||||||
// Create Summoner's MatchList in Database
|
}))
|
||||||
summonerDB.matchList = matchList
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.timeEnd('matchList')
|
console.timeEnd('matchList')
|
||||||
|
return currentMatchListIds.reverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch list of matches for a specific Summoner
|
* Fetch list of matches for a specific Summoner
|
||||||
* @param puuid
|
|
||||||
* @param accountId
|
|
||||||
* @param region
|
|
||||||
* @param gameIds
|
|
||||||
* @param summonerDB
|
|
||||||
*/
|
*/
|
||||||
public async getMatches (puuid: string, accountId: string, region: string, matchIds: MatchlistDto, summonerDB: SummonerModel) {
|
public async getMatches(
|
||||||
|
region: string,
|
||||||
|
matchIds: string[],
|
||||||
|
puuid: string
|
||||||
|
): Promise<SerializedMatch[]> {
|
||||||
console.time('getMatches')
|
console.time('getMatches')
|
||||||
|
|
||||||
let matchesDetails: MatchModel[] = []
|
const matches: SerializedMatch[] = []
|
||||||
const matchesToGetFromRiot: MatchlistDto = []
|
const matchesToGetFromRiot: MatchlistDto = []
|
||||||
for (let i = 0; i < matchIds.length; ++i) {
|
for (let i = 0; i < matchIds.length; ++i) {
|
||||||
const matchSaved = await Match.findOne({
|
const matchSaved = await Match.query()
|
||||||
summoner_puuid: puuid,
|
.where('id', matchIds[i])
|
||||||
matchId: matchIds[i],
|
.preload('teams')
|
||||||
})
|
.preload('players')
|
||||||
|
.first()
|
||||||
|
|
||||||
if (matchSaved) {
|
if (matchSaved) {
|
||||||
matchesDetails.push(matchSaved)
|
// TODO: Serialize match from DB + put it in Redis + push it in "matches"
|
||||||
|
matches.push(BasicMatchSerializer.serializeOneMatch(matchSaved, puuid))
|
||||||
} else {
|
} else {
|
||||||
matchesToGetFromRiot.push(matchIds[i])
|
matchesToGetFromRiot.push(matchIds[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const requests = matchesToGetFromRiot.map(gameId => Jax.Match.get(gameId, region))
|
const requests = matchesToGetFromRiot.map((gameId) => Jax.Match.get(gameId, region))
|
||||||
let matchesFromApi = await Promise.all(requests)
|
const matchesFromApi = await Promise.all(requests)
|
||||||
|
|
||||||
/* If we have to store some matches in the db */
|
/* If we have to store some matches in the db */
|
||||||
if (matchesFromApi.length !== 0) {
|
if (matchesFromApi.length !== 0) {
|
||||||
// Try to see why matches are sometimes undefined
|
// Remove bugged matches from the Riot API + tutorial games
|
||||||
matchesFromApi.filter(m => {
|
const filteredMatches = matchesFromApi
|
||||||
if (m === undefined) {
|
.filter(notEmpty)
|
||||||
Logger.info(`Match undefined, summoner: ${summonerDB.puuid}`, m)
|
.filter(
|
||||||
}
|
(m) =>
|
||||||
})
|
!tutorialQueues.includes(m.info.queueId) &&
|
||||||
|
m.info.teams.length > 0 &&
|
||||||
|
m.info.participants.length > 0
|
||||||
|
)
|
||||||
|
|
||||||
// Transform raw matches data
|
// Transform raw matches data
|
||||||
const transformedMatches = await BasicMatchTransformer.transform(matchesFromApi, { puuid, accountId })
|
const parsedMatches: any = await MatchParser.parse(filteredMatches)
|
||||||
|
|
||||||
/* Save all matches from Riot Api in db */
|
// TODO: Serialize match from DB + put it in Redis + push it in "matches"
|
||||||
for (const match of transformedMatches) {
|
const serializedMatches = BasicMatchSerializer.serialize(parsedMatches, puuid, true)
|
||||||
await Match.create(match)
|
matches.push(...serializedMatches)
|
||||||
match.newMatch = true
|
|
||||||
}
|
|
||||||
matchesDetails = [...matchesDetails, ...transformedMatches]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort matches */
|
// Todo: check if we need to sort here
|
||||||
matchesDetails.sort((a, b) => (a.date < b.date) ? 1 : -1)
|
matches.sort((a, b) => (a.date < b.date ? 1 : -1))
|
||||||
console.timeEnd('getMatches')
|
console.timeEnd('getMatches')
|
||||||
|
return matches
|
||||||
return matchesDetails
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue