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,
|
||||
"commands": [
|
||||
"./commands",
|
||||
"@adonisjs/core/build/commands",
|
||||
"@zakodium/adonis-mongodb/lib/commands"
|
||||
"@adonisjs/core/build/commands/index.js",
|
||||
"@adonisjs/repl/build/commands",
|
||||
"@adonisjs/lucid/build/commands"
|
||||
],
|
||||
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
||||
"aliases": {
|
||||
"App": "app",
|
||||
"Contracts": "contracts",
|
||||
"Config": "config",
|
||||
"Database": "database"
|
||||
"Database": "database",
|
||||
"Contracts": "contracts"
|
||||
},
|
||||
"preloads": [
|
||||
"./start/routes",
|
||||
"./start/kernel"
|
||||
"./start/kernel",
|
||||
{
|
||||
"file": "./start/events",
|
||||
"environment": [
|
||||
"console",
|
||||
"repl",
|
||||
"web"
|
||||
]
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
"./providers/AppProvider",
|
||||
"@adonisjs/core",
|
||||
"@zakodium/adonis-mongodb",
|
||||
"@adonisjs/lucid",
|
||||
"@adonisjs/redis"
|
||||
],
|
||||
"metaFiles": [
|
||||
".env",
|
||||
".adonisrc.json"
|
||||
"aceProviders": [
|
||||
"@adonisjs/repl"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,18 @@ PORT=3333
|
|||
HOST=0.0.0.0
|
||||
NODE_ENV=development
|
||||
APP_KEY=
|
||||
DRIVE_DISK=local
|
||||
|
||||
MONGODB_URL=mongodb://localhost:27017
|
||||
MONGODB_DATABASE=leaguestats
|
||||
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=
|
||||
|
||||
API_KEY=RGAPI-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
RIOT_API_KEY=
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
{
|
||||
"extends": [
|
||||
"plugin:adonis/typescriptApp"
|
||||
],
|
||||
"extends": ["plugin:adonis/typescriptApp", "prettier"],
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 130
|
||||
}
|
||||
]
|
||||
"prettier/prettier": ["error"]
|
||||
}
|
||||
}
|
||||
1
server/.gitignore
vendored
1
server/.gitignore
vendored
|
|
@ -5,4 +5,3 @@ coverage
|
|||
.DS_STORE
|
||||
.env
|
||||
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
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is the entry point for running ace commands. For typescript
|
||||
| projects, the ace commands will fallback to the compiled code and
|
||||
| hence this file has to be executable by node directly.
|
||||
| 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/src/Ignitor')
|
||||
const { Ignitor } = require('@adonisjs/core/build/standalone')
|
||||
new Ignitor(__dirname)
|
||||
.ace()
|
||||
.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,10 +1,10 @@
|
|||
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'
|
||||
import RuneTransformer from 'App/Transformers/RuneTransformer'
|
||||
|
||||
export default class CDragonController {
|
||||
public async runes ({ response }: HttpContextContract) {
|
||||
public async runes({ response }: HttpContextContract) {
|
||||
const cacheUrl = 'cdragon-runes'
|
||||
|
||||
const requestCached = await Redis.get(cacheUrl)
|
||||
|
|
@ -16,8 +16,8 @@ export default class CDragonController {
|
|||
const perkstyles = await Jax.CDragon.perkstyles()
|
||||
|
||||
const runesData = {
|
||||
perks: RuneTransformer.transformPerks(perks),
|
||||
perkstyles: RuneTransformer.transformStyles(perkstyles.styles),
|
||||
perks: RuneSerializer.serializePerks(perks),
|
||||
perkstyles: RuneSerializer.serializeStyles(perkstyles.styles),
|
||||
}
|
||||
|
||||
await Redis.set(cacheUrl, JSON.stringify(runesData), 'EX', 36000)
|
||||
|
|
|
|||
|
|
@ -1,53 +1,23 @@
|
|||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
import DetailedMatch, { DetailedMatchModel } from 'App/Models/DetailedMatch'
|
||||
import { ParticipantDetails } from 'App/Models/Match'
|
||||
import Summoner from 'App/Models/Summoner'
|
||||
import Jax from 'App/Services/Jax'
|
||||
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 SummonerService from 'App/Services/SummonerService'
|
||||
import DetailedMatchTransformer from 'App/Transformers/DetailedMatchTransformer'
|
||||
import DetailedMatchValidator from 'App/Validators/DetailedMatchValidator'
|
||||
import MatchesIndexValidator from 'App/Validators/MatchesIndexValidator'
|
||||
|
||||
export default class MatchesController {
|
||||
/**
|
||||
* Get the soloQ rank of all the players of the team
|
||||
* @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
|
||||
* POST - Return data from matches searched by matchIds
|
||||
* @param ctx
|
||||
*/
|
||||
public async index ({ request, response }: HttpContextContract) {
|
||||
console.log('More Matches Request')
|
||||
const { puuid, accountId, region, gameIds, season } = await request.validate(MatchesIndexValidator)
|
||||
|
||||
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()
|
||||
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,
|
||||
|
|
@ -58,27 +28,25 @@ export default class MatchesController {
|
|||
* POST - Return details data for one specific match
|
||||
* @param ctx
|
||||
*/
|
||||
public async show ({ request, response }: HttpContextContract) {
|
||||
public async show({ request, response }: HttpContextContract) {
|
||||
console.time('MatchDetails')
|
||||
const { gameId, region } = await request.validate(DetailedMatchValidator)
|
||||
const { matchId } = await request.validate(DetailedMatchValidator)
|
||||
|
||||
let matchDetails: DetailedMatchModel
|
||||
const alreadySaved = await DetailedMatch.findOne({ gameId, region })
|
||||
const match = await Match.query()
|
||||
.where('id', matchId)
|
||||
.preload('teams')
|
||||
.preload('players', (playersQuery) => {
|
||||
playersQuery.preload('ranks')
|
||||
})
|
||||
.firstOrFail()
|
||||
|
||||
if (alreadySaved) {
|
||||
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)
|
||||
}
|
||||
const { match: matchDetails, ranksLoaded } = DetailedMatchSerializer.serializeOneMatch(match)
|
||||
|
||||
console.timeEnd('MatchDetails')
|
||||
|
||||
return response.json({
|
||||
matchDetails,
|
||||
ranksLoaded,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -86,28 +54,14 @@ export default class MatchesController {
|
|||
* POST - Return ranks of players for a specific game
|
||||
* @param ctx
|
||||
*/
|
||||
public async showRanks ({ request, response }: HttpContextContract) {
|
||||
public async showRanks({ request, response }: HttpContextContract) {
|
||||
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')
|
||||
|
||||
return response.json({
|
||||
blueTeam: matchDetails.blueTeam.players,
|
||||
redTeam: matchDetails.redTeam.players,
|
||||
})
|
||||
return response.json(serializedRanks)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ 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 LiveMatchTransformer from 'App/Transformers/LiveMatchTransformer'
|
||||
import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator'
|
||||
import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator'
|
||||
import SummonerLiveValidator from 'App/Validators/SummonerLiveValidator'
|
||||
|
|
@ -14,21 +15,8 @@ import SummonerOverviewValidator from 'App/Validators/SummonerOverviewValidator'
|
|||
import SummonerRecordValidator from 'App/Validators/SummonerRecordValidator'
|
||||
|
||||
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) {
|
||||
console.time('all')
|
||||
public async basic({ request, response }: HttpContextContract) {
|
||||
console.time('BASIC_REQUEST')
|
||||
const { summoner, region } = await request.validate(SummonerBasicValidator)
|
||||
const finalJSON: any = {}
|
||||
|
||||
|
|
@ -38,24 +26,20 @@ export default class SummonersController {
|
|||
if (!account) {
|
||||
return response.json(null)
|
||||
}
|
||||
account.region = region
|
||||
finalJSON.account = account
|
||||
|
||||
// Summoner in DB
|
||||
let summonerDB = await Summoner.findOne({ puuid: account.puuid })
|
||||
if (!summonerDB) {
|
||||
summonerDB = await Summoner.create({ puuid: account.puuid })
|
||||
}
|
||||
const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid })
|
||||
|
||||
// Summoner names
|
||||
finalJSON.account.names = SummonerService.getAllSummonerNames(account, summonerDB)
|
||||
finalJSON.account.names = await SummonerService.getAllSummonerNames(account, summonerDB)
|
||||
|
||||
// MATCH LIST
|
||||
await MatchService.updateMatchList(account, summonerDB)
|
||||
finalJSON.matchList = summonerDB.matchList
|
||||
finalJSON.matchList = await MatchService.updateMatchList(account, region, summonerDB)
|
||||
|
||||
// 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
|
||||
const currentGame = await Jax.Spectator.summonerID(account.id, region)
|
||||
|
|
@ -63,52 +47,44 @@ export default class SummonersController {
|
|||
finalJSON.current = currentGame
|
||||
|
||||
// RANKED STATS
|
||||
finalJSON.ranked = await SummonerService.getRanked(account, region)
|
||||
finalJSON.ranked = await SummonerService.getRanked(account.id, region)
|
||||
|
||||
// SAVE IN DB
|
||||
await summonerDB.save()
|
||||
} catch (error) {
|
||||
console.log('username not found')
|
||||
console.log(error)
|
||||
// RECENT ACTIVITY
|
||||
finalJSON.recentActivity = await StatsService.getRecentActivity(account.puuid)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
console.timeEnd('BASIC_REQUEST')
|
||||
return response.json(null)
|
||||
}
|
||||
|
||||
console.timeEnd('all')
|
||||
console.timeEnd('BASIC_REQUEST')
|
||||
return response.json(finalJSON)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST: get overview view summoner data
|
||||
* @param ctx
|
||||
*/
|
||||
public async overview ({ request, response }: HttpContextContract) {
|
||||
console.time('overview')
|
||||
const { puuid, accountId, region, season } = await request.validate(SummonerOverviewValidator)
|
||||
public async overview({ request, response }: HttpContextContract) {
|
||||
console.time('OVERVIEW_REQUEST')
|
||||
const { puuid, region, season } = await request.validate(SummonerOverviewValidator)
|
||||
const finalJSON: any = {}
|
||||
|
||||
// Summoner in DB
|
||||
let summonerDB = await Summoner.findOne({ puuid: puuid })
|
||||
if (!summonerDB) {
|
||||
summonerDB = await Summoner.create({ puuid: puuid })
|
||||
}
|
||||
const summonerDB = await Summoner.firstOrCreate({ puuid: puuid })
|
||||
|
||||
// MATCHES BASIC
|
||||
const gameIds = summonerDB.matchList!.slice(0)
|
||||
// .filter(m => {
|
||||
// return season ? m.seasonMatch === season : true // TODO: filter by season
|
||||
// })
|
||||
.slice(0, 10)
|
||||
finalJSON.matchesDetails = await MatchService.getMatches(puuid, accountId, region, gameIds, summonerDB)
|
||||
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)
|
||||
|
||||
// STATS
|
||||
console.time('STATS')
|
||||
finalJSON.stats = await StatsService.getSummonerStats(puuid, season)
|
||||
console.timeEnd('STATS')
|
||||
|
||||
// SAVE IN DB
|
||||
await summonerDB.save()
|
||||
|
||||
console.timeEnd('overview')
|
||||
console.timeEnd('OVERVIEW_REQUEST')
|
||||
return response.json(finalJSON)
|
||||
}
|
||||
|
||||
|
|
@ -116,44 +92,57 @@ export default class SummonersController {
|
|||
* POST: get champions view summoner data
|
||||
* @param ctx
|
||||
*/
|
||||
public async champions ({ request, response }: HttpContextContract) {
|
||||
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(championStats)
|
||||
return response.json(championStatsSerialized)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST: get records view summoner data
|
||||
* @param ctx
|
||||
*/
|
||||
public async records ({ request, response }: HttpContextContract) {
|
||||
public async records({ request, response }: HttpContextContract) {
|
||||
console.time('recordsRequest')
|
||||
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')
|
||||
return response.json(records)
|
||||
return response.json(recordsSerialized)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST - Return live match detail
|
||||
* @param ctx
|
||||
*/
|
||||
public async liveMatchDetails ({ request, response }: HttpContextContract) {
|
||||
public async liveMatchDetails({ request, response }: HttpContextContract) {
|
||||
console.time('liveMatchDetails')
|
||||
const { id, region } = await request.validate(SummonerLiveValidator)
|
||||
|
||||
// CURRENT GAME
|
||||
let currentGame = await Jax.Spectator.summonerID(id, region)
|
||||
const currentGame = await Jax.Spectator.summonerID(id, region)
|
||||
|
||||
if (!currentGame) {
|
||||
return response.json(null)
|
||||
}
|
||||
|
||||
currentGame = await LiveMatchTransformer.transform(currentGame, { region })
|
||||
const currentGameSerialized = await LiveMatchSerializer.serializeOneMatch(currentGame, region)
|
||||
console.timeEnd('liveMatchDetails')
|
||||
|
||||
return response.json(currentGame)
|
||||
return response.json(currentGameSerialized)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import Logger from '@ioc:Adonis/Core/Logger'
|
|||
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
|
||||
|
||||
export default class ExceptionHandler extends HttpExceptionHandler {
|
||||
constructor () {
|
||||
constructor() {
|
||||
super(Logger)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
account_id: string,
|
||||
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,
|
||||
export default class Match extends BaseModel {
|
||||
public static selfAssignPrimaryKey = true
|
||||
|
||||
// V5
|
||||
matchId: string,
|
||||
}
|
||||
@column({ isPrimary: true })
|
||||
public id: string
|
||||
|
||||
export interface ParticipantDetails {
|
||||
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
|
||||
@column()
|
||||
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
|
||||
public matchId: string
|
||||
@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,21 +1,36 @@
|
|||
import { Model } from '@ioc:Mongodb/Model'
|
||||
import { MatchlistDto } from 'App/Services/Jax/src/Endpoints/MatchlistEndpoint'
|
||||
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 interface SummonerModel {
|
||||
puuid: string,
|
||||
matchList?: MatchlistDto,
|
||||
names?: SummonerNames[]
|
||||
}
|
||||
|
||||
interface SummonerNames {
|
||||
name: string,
|
||||
date: Date
|
||||
}
|
||||
|
||||
export default class Summoner extends Model implements SummonerModel {
|
||||
public static collectionName = 'summoners'
|
||||
export default class Summoner extends BaseModel {
|
||||
public static selfAssignPrimaryKey = true
|
||||
|
||||
@column({ isPrimary: true })
|
||||
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 { Collection } from 'mongodb'
|
||||
import Database from '@ioc:Adonis/Lucid/Database'
|
||||
|
||||
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 () {
|
||||
this.getCollection()
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic matchParams used in a lot of requests
|
||||
* @param puuid of the summoner
|
||||
*/
|
||||
private matchParams (puuid: string, season?: number) {
|
||||
return {
|
||||
summoner_puuid: puuid,
|
||||
result: { $not: { $eq: 'Remake' } },
|
||||
gamemode: { $nin: [800, 810, 820, 830, 840, 850, 2000, 2010, 2020] },
|
||||
season: season ? season : { $exists: true },
|
||||
}
|
||||
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]
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the aggregate mongo query
|
||||
* @param puuid
|
||||
* @param matchParams
|
||||
* @param intermediateSteps
|
||||
* @param groupId
|
||||
* @param groupParams
|
||||
* @param finalSteps
|
||||
*/
|
||||
private async aggregate (
|
||||
puuid: string,
|
||||
matchParams: object,
|
||||
intermediateSteps: any[],
|
||||
groupId: any,
|
||||
groupParams: object,
|
||||
finalSteps: any[],
|
||||
season?: number,
|
||||
) {
|
||||
return this.collection.aggregate([
|
||||
{
|
||||
$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 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
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MongoDB matches collection
|
||||
*/
|
||||
public async getCollection () {
|
||||
if (!this.collection) {
|
||||
this.collection = await mongodb.connection().collection('matches')
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Summoner's statistics for the N most played champions
|
||||
* @param puuid of the summoner
|
||||
* @param limit number of champions to fetch
|
||||
* @param season
|
||||
*/
|
||||
public async championStats (puuid: string, limit = 5, season?: number) {
|
||||
const groupParams = {
|
||||
champion: { $first: '$champion' },
|
||||
kills: { $sum: '$stats.kills' },
|
||||
deaths: { $sum: '$stats.deaths' },
|
||||
assists: { $sum: '$stats.assists' },
|
||||
}
|
||||
const finalSteps = [
|
||||
{ $sort: { 'count': -1, 'champion.name': 1 } },
|
||||
{ $limit: limit },
|
||||
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',
|
||||
]
|
||||
return this.aggregate(puuid, {}, [], '$champion.id', groupParams, finalSteps, season)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Summoner's statistics for all played champion classes
|
||||
* @param puuid of the summoner
|
||||
* @param season
|
||||
*/
|
||||
public async championClassStats (puuid: string, season?: number) {
|
||||
const groupId = { '$arrayElemAt': ['$champion.roles', 0] }
|
||||
return this.aggregate(puuid, {}, [], groupId, {}, [], season)
|
||||
}
|
||||
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 ')
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
const matchParams = queue ? { gamemode: { $eq: Number(queue) } } : {}
|
||||
const groupParams = {
|
||||
time: { $sum: '$time' },
|
||||
gameLength: { $avg: '$time' },
|
||||
date: { $max: '$date' },
|
||||
champion: { $first: '$champion' },
|
||||
kills: { $sum: '$stats.kills' },
|
||||
deaths: { $sum: '$stats.deaths' },
|
||||
assists: { $sum: '$stats.assists' },
|
||||
minions: { $avg: '$stats.minions' },
|
||||
gold: { $avg: '$stats.gold' },
|
||||
dmgChamp: { $avg: '$stats.dmgChamp' },
|
||||
dmgTaken: { $avg: '$stats.dmgTaken' },
|
||||
kp: { $avg: '$stats.kp' },
|
||||
}
|
||||
const finalSteps = [
|
||||
{ $sort: { 'count': -1, 'champion.name': 1 } },
|
||||
]
|
||||
return this.aggregate(puuid, matchParams, [], '$champion.id', groupParams, finalSteps, season)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Summoner's statistics for all played modes
|
||||
* @param puuid of the summoner
|
||||
* @param season
|
||||
*/
|
||||
public async gamemodeStats (puuid: string, season?: number) {
|
||||
return this.aggregate(puuid, {}, [], '$gamemode', {}, [], season)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global Summoner's statistics
|
||||
* @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)
|
||||
const { rows } = await Database.rawQuery(query, { puuid })
|
||||
return rows
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import Env from '@ioc:Adonis/Core/Env'
|
||||
|
||||
export interface JaxConfig {
|
||||
key: string,
|
||||
region: string,
|
||||
key: string
|
||||
region: string
|
||||
requestOptions: JaxConfigRequestOptions
|
||||
}
|
||||
|
||||
export interface JaxConfigRequestOptions {
|
||||
retriesBeforeAbort: number,
|
||||
delayBeforeRetry: number,
|
||||
retriesBeforeAbort: number
|
||||
delayBeforeRetry: number
|
||||
}
|
||||
|
||||
export const JAX_CONFIG: JaxConfig = {
|
||||
key: Env.get('API_KEY') as string,
|
||||
key: Env.get('RIOT_API_KEY') as string,
|
||||
region: 'euw1',
|
||||
requestOptions: {
|
||||
retriesBeforeAbort: 3,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export default class CDragonRequest {
|
|||
private retries: number
|
||||
private sleep: { (ms: number): Promise<void>; <T>(ms: number, value: T): Promise<T> }
|
||||
|
||||
constructor (config: JaxConfig, endpoint: string, cacheTime: number) {
|
||||
constructor(config: JaxConfig, endpoint: string, cacheTime: number) {
|
||||
this.config = config
|
||||
this.endpoint = endpoint
|
||||
this.cacheTime = cacheTime
|
||||
|
|
@ -26,7 +26,7 @@ export default class CDragonRequest {
|
|||
// 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 () {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -2,103 +2,103 @@ import { JaxConfig } from '../../JaxConfig'
|
|||
import CDragonRequest from '../CDragonRequest'
|
||||
|
||||
export interface ChampionDTO {
|
||||
id: number,
|
||||
name: string,
|
||||
alias: string,
|
||||
squarePortraitPath: string,
|
||||
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,
|
||||
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,
|
||||
id: number
|
||||
name: string
|
||||
majorChangePatchVersion: string
|
||||
tooltip: string
|
||||
shortDesc: string
|
||||
longDesc: string
|
||||
iconPath: string
|
||||
endOfGameStatDescs: string[]
|
||||
}
|
||||
|
||||
export interface PerkStyleResponse {
|
||||
schemaVersion: string,
|
||||
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[] }[]
|
||||
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[],
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
summonerLevel: number
|
||||
cooldown: number
|
||||
gameModes: string[]
|
||||
iconPath: string
|
||||
}
|
||||
|
||||
export default class CDragonEndpoint {
|
||||
private config: JaxConfig
|
||||
|
||||
constructor (config: JaxConfig) {
|
||||
constructor(config: JaxConfig) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
public async champions (): Promise<ChampionDTO[]> {
|
||||
public async champions(): Promise<ChampionDTO[]> {
|
||||
return new CDragonRequest(this.config, 'champion-summary.json', 36000).execute()
|
||||
}
|
||||
|
||||
public async items (): Promise<ItemDTO[]> {
|
||||
public async items(): Promise<ItemDTO[]> {
|
||||
return new CDragonRequest(this.config, 'items.json', 36000).execute()
|
||||
}
|
||||
|
||||
public async perks (): Promise<PerkDTO[]> {
|
||||
public async perks(): Promise<PerkDTO[]> {
|
||||
return new CDragonRequest(this.config, 'perks.json', 36000).execute()
|
||||
}
|
||||
|
||||
public async perkstyles (): Promise<PerkStyleResponse> {
|
||||
public async perkstyles(): Promise<PerkStyleResponse> {
|
||||
return new CDragonRequest(this.config, 'perkstyles.json', 36000).execute()
|
||||
}
|
||||
|
||||
public async summonerSpells (): Promise<SummonerSpellDTO[]> {
|
||||
public async summonerSpells(): Promise<SummonerSpellDTO[]> {
|
||||
return new CDragonRequest(this.config, 'summoner-spells.json', 36000).execute()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,26 +4,26 @@ 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;
|
||||
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,
|
||||
losses: number
|
||||
progress: string
|
||||
target: number
|
||||
wins: number
|
||||
}
|
||||
|
||||
|
|
@ -31,12 +31,12 @@ export default class LeagueEndpoint {
|
|||
private config: JaxConfig
|
||||
private limiter: RiotRateLimiter
|
||||
|
||||
constructor (config: JaxConfig, limiter: RiotRateLimiter) {
|
||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
||||
this.config = config
|
||||
this.limiter = limiter
|
||||
}
|
||||
|
||||
public summonerID (summonerID: string, region: string): Promise<LeagueEntryDTO[]> {
|
||||
public summonerID(summonerID: string, region: string): Promise<LeagueEntryDTO[]> {
|
||||
return new JaxRequest(
|
||||
region,
|
||||
this.config,
|
||||
|
|
|
|||
|
|
@ -4,424 +4,209 @@ import RiotRateLimiter from 'riot-ratelimiter'
|
|||
import { JaxConfig } from '../../JaxConfig'
|
||||
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 {
|
||||
metadata: MetadataDto;
|
||||
info: InfoDto;
|
||||
metadata: MetadataDto
|
||||
info: InfoDto
|
||||
}
|
||||
|
||||
export interface MetadataDto {
|
||||
dataVersion: string;
|
||||
matchId: string;
|
||||
participants: string[];
|
||||
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;
|
||||
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;
|
||||
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
|
||||
Assasin,
|
||||
}
|
||||
|
||||
export type LaneDto = 'TOP' | 'JUNGLE' |'MIDDLE' | 'BOTTOM'
|
||||
export type LaneDto = 'TOP' | 'JUNGLE' | 'MIDDLE' | 'BOTTOM'
|
||||
|
||||
export interface PerksDto {
|
||||
statPerks: PerkStatsDto;
|
||||
styles: PerkStyleDto[];
|
||||
statPerks: PerkStatsDto
|
||||
styles: PerkStyleDto[]
|
||||
}
|
||||
|
||||
export interface PerkStatsDto {
|
||||
defense: number;
|
||||
flex: number;
|
||||
offense: number;
|
||||
defense: number
|
||||
flex: number
|
||||
offense: number
|
||||
}
|
||||
|
||||
export interface PerkStyleDto {
|
||||
description: 'primaryStyle' | 'subStyle';
|
||||
selections: PerkStyleSelectionDto[];
|
||||
style: number;
|
||||
description: 'primaryStyle' | 'subStyle'
|
||||
selections: PerkStyleSelectionDto[]
|
||||
style: number
|
||||
}
|
||||
|
||||
export interface PerkStyleSelectionDto {
|
||||
perk: number;
|
||||
var1: number;
|
||||
var2: number;
|
||||
var3: number;
|
||||
perk: number
|
||||
var1: number
|
||||
var2: number
|
||||
var3: number
|
||||
}
|
||||
|
||||
export type RoleDto = 'NONE' | 'DUO' |'SOLO' | 'CARRY' | 'SUPPORT'
|
||||
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 {
|
||||
bans: BanDto[];
|
||||
objectives: ObjectivesDto;
|
||||
teamId: number;
|
||||
win: boolean;
|
||||
bans: BanDto[]
|
||||
objectives: ObjectivesDto
|
||||
teamId: number
|
||||
win: boolean
|
||||
}
|
||||
|
||||
export interface BanDto {
|
||||
championId: number;
|
||||
pickTurn: number;
|
||||
championId: number
|
||||
pickTurn: number
|
||||
}
|
||||
|
||||
export interface ObjectivesDto {
|
||||
baron: ObjectiveDto;
|
||||
champion: ObjectiveDto;
|
||||
dragon: ObjectiveDto;
|
||||
inhibitor: ObjectiveDto;
|
||||
riftHerald: ObjectiveDto;
|
||||
tower: ObjectiveDto;
|
||||
baron: ObjectiveDto
|
||||
champion: ObjectiveDto
|
||||
dragon: ObjectiveDto
|
||||
inhibitor: ObjectiveDto
|
||||
riftHerald: ObjectiveDto
|
||||
tower: ObjectiveDto
|
||||
}
|
||||
|
||||
export interface ObjectiveDto {
|
||||
first: boolean;
|
||||
kills: number;
|
||||
first: boolean
|
||||
kills: number
|
||||
}
|
||||
|
||||
export default class MatchEndpoint {
|
||||
private config: JaxConfig
|
||||
private limiter: RiotRateLimiter
|
||||
|
||||
constructor (config: JaxConfig, 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> {
|
||||
public get(matchID: string, region: string): Promise<MatchDto> {
|
||||
return new JaxRequest(
|
||||
getRiotRegion(region),
|
||||
this.config,
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ export default class MatchlistEndpoint {
|
|||
private config: JaxConfig
|
||||
private limiter: RiotRateLimiter
|
||||
|
||||
constructor (config: JaxConfig, 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> {
|
||||
public puuid(puuid: string, region: string, beginIndex = 0, count = 100): Promise<MatchlistDto> {
|
||||
return new JaxRequest(
|
||||
getRiotRegion(region),
|
||||
this.config,
|
||||
|
|
|
|||
|
|
@ -1,59 +1,53 @@
|
|||
// import { RiotRateLimiter } from '@fightmegg/riot-rate-limiter'
|
||||
import RiotRateLimiter from 'riot-ratelimiter'
|
||||
import { LeagueEntriesByQueue } from 'App/Services/SummonerService'
|
||||
import { JaxConfig } from '../../JaxConfig'
|
||||
import JaxRequest from '../JaxRequest'
|
||||
|
||||
export interface CurrentGameInfo {
|
||||
gameId: number,
|
||||
export interface CurrentGameInfoDTO {
|
||||
gameId: number
|
||||
gameType: string
|
||||
gameStartTime: number,
|
||||
mapId: number,
|
||||
gameLength: number,
|
||||
platformId: string,
|
||||
gameMode: string,
|
||||
bannedChampions: BannedChampion[],
|
||||
gameQueueConfigId: number,
|
||||
observers: Observer,
|
||||
participants: CurrentGameParticipant[],
|
||||
gameStartTime: number
|
||||
mapId: number
|
||||
gameLength: number
|
||||
platformId: string
|
||||
gameMode: string
|
||||
bannedChampions: BannedChampionDTO[]
|
||||
gameQueueConfigId: number
|
||||
observers: ObserverDTO
|
||||
participants: CurrentGameParticipantDTO[]
|
||||
}
|
||||
|
||||
export interface BannedChampion {
|
||||
pickTurn: number,
|
||||
championId: number,
|
||||
teamId: number,
|
||||
export interface BannedChampionDTO {
|
||||
pickTurn: number
|
||||
championId: number
|
||||
teamId: number
|
||||
}
|
||||
|
||||
export interface Observer {
|
||||
encryptionKey: string,
|
||||
export interface ObserverDTO {
|
||||
encryptionKey: string
|
||||
}
|
||||
|
||||
export interface CurrentGameParticipant {
|
||||
championId: number,
|
||||
perks: Perks,
|
||||
profileIconId: number,
|
||||
bot: boolean,
|
||||
teamId: number,
|
||||
summonerName: string,
|
||||
summonerId: string,
|
||||
spell1Id: number,
|
||||
spell2Id: number,
|
||||
gameCustomizationObjects: GameCustomizationObject[],
|
||||
// Custom types from here
|
||||
role?: string,
|
||||
runes?: { primaryRune: string, secondaryRune: string } | {}
|
||||
level?: number,
|
||||
rank?: LeagueEntriesByQueue
|
||||
export interface CurrentGameParticipantDTO {
|
||||
championId: number
|
||||
perks: PerksDTO
|
||||
profileIconId: number
|
||||
bot: boolean
|
||||
teamId: number
|
||||
summonerName: string
|
||||
summonerId: string
|
||||
spell1Id: number
|
||||
spell2Id: number
|
||||
gameCustomizationObjects: GameCustomizationObjectDTO[]
|
||||
}
|
||||
|
||||
export interface Perks {
|
||||
export interface PerksDTO {
|
||||
perkIds: number[]
|
||||
perkStyle: number,
|
||||
perkStyle: number
|
||||
perkSubStyle: number
|
||||
}
|
||||
|
||||
export interface GameCustomizationObject {
|
||||
category: string,
|
||||
export interface GameCustomizationObjectDTO {
|
||||
category: string
|
||||
content: string
|
||||
}
|
||||
|
||||
|
|
@ -61,12 +55,12 @@ export default class SpectatorEndpoint {
|
|||
private config: JaxConfig
|
||||
private limiter: RiotRateLimiter
|
||||
|
||||
constructor (config: JaxConfig, limiter: RiotRateLimiter) {
|
||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
||||
this.config = config
|
||||
this.limiter = limiter
|
||||
}
|
||||
|
||||
public summonerID (summonerID: string, region: string) {
|
||||
public summonerID(summonerID: string, region: string): Promise<CurrentGameInfoDTO | undefined> {
|
||||
return new JaxRequest(
|
||||
region,
|
||||
this.config,
|
||||
|
|
|
|||
|
|
@ -4,26 +4,35 @@ import { JaxConfig } from '../../JaxConfig'
|
|||
import JaxRequest from '../JaxRequest'
|
||||
|
||||
export interface SummonerDTO {
|
||||
accountId: string,
|
||||
profileIconId: number,
|
||||
revisionDate: number,
|
||||
name: string,
|
||||
id: string,
|
||||
puuid: string,
|
||||
summonerLevel: number,
|
||||
region?: string
|
||||
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) {
|
||||
constructor(config: JaxConfig, limiter: RiotRateLimiter) {
|
||||
this.config = config
|
||||
this.limiter = limiter
|
||||
}
|
||||
|
||||
public summonerId (summonerId: string, region: string): Promise<SummonerDTO> {
|
||||
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,
|
||||
|
|
@ -33,7 +42,7 @@ export default class SummonerEndpoint {
|
|||
).execute()
|
||||
}
|
||||
|
||||
public summonerName (summonerName: string, region: string): Promise<SummonerDTO> {
|
||||
public summonerName(summonerName: string, region: string): Promise<SummonerDTO> {
|
||||
return new JaxRequest(
|
||||
region,
|
||||
this.config,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue