Skip to content

Commit

Permalink
Added Season Events Preprocess
Browse files Browse the repository at this point in the history
  • Loading branch information
ichenglin committed Jan 27, 2024
1 parent 9e886d5 commit 72a4e75
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 29 deletions.
4 changes: 2 additions & 2 deletions commands/command_skills.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AttachmentBuilder, ChatInputCommandInteraction, EmbedBuilder, InteractionEditReplyOptions, MessagePayload, SlashCommandBuilder } from "discord.js";
import * as NodeChartJS from "chartjs-node-canvas";
import RobotEvent, { SeasonData } from "../objects/robotevent";
import RobotEvent, { SeasonDataSimplified } from "../objects/robotevent";
import VerificationCommand from "../templates/template_command";
import VerificationDisplay from "../utilities/display";

Expand Down Expand Up @@ -43,7 +43,7 @@ export default class SkillsCommand extends VerificationCommand {
await command_interaction.editReply({embeds: [invalid_embed]});
return;
}
const team_season_data: SeasonData[] = [];
const team_season_data: SeasonDataSimplified[] = [];
for (let skill_index = 0; skill_index < team_skills.length; skill_index++) {
const skill_data = team_skills[skill_index];
// if driver score and programming score is both 0, won't exist in season skill
Expand Down
8 changes: 8 additions & 0 deletions events/event_ready.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Client } from "discord.js";
import Logger from "../objects/logger";
import VerificationEvent from "../templates/template_event";
import PreProcess from "../objects/preprocess";

export default class ReadyEvent extends VerificationEvent {

Expand All @@ -12,6 +13,13 @@ export default class ReadyEvent extends VerificationEvent {

public async event_trigger(client: Client): Promise<void> {
Logger.send_log("Verification bot is now online.");
// repeat preprocess
await this.preprocess_fetch();
setInterval(this.preprocess_fetch, parseInt(process.env.REDIS_CACHE_LIFESPAN as string) * (1E3));
}

public async preprocess_fetch(): Promise<void> {
await PreProcess.preprocess_event_season();
}

}
53 changes: 53 additions & 0 deletions objects/preprocess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import AsyncDelay from "../utilities/async_delay";
import VerificationCache from "./cache";
import Logger from "./logger";
import RobotEvent, { EventData, SeasonData } from "./robotevent";

export default class PreProcess {

private static processed_season_data: SeasonDataEvents[] = [];

// only process seasons with the following programs
private static readonly SEASON_PROGRAM_CODES: string[] = ["VRC", "VEXU"];

public static get_event_season(event_id: number): any {

}

public static async preprocess_event_season(): Promise<void> {
const seasons_list = (await RobotEvent.get_seasons()).filter(season_data => PreProcess.SEASON_PROGRAM_CODES.includes(season_data.season_program.program_code));
const seasons_events = [] as EventData[][];
for (const season_data of seasons_list) {
const cache_exist = (await VerificationCache.cache_get(`ROBOTEVENT_SEASONEVENTS_${season_data.season_id}`)) !== undefined;
seasons_events.push(await RobotEvent.get_season_events(season_data.season_id, season_data.season_date.date_end));
if (!cache_exist) await AsyncDelay.async_delay(10 * 1E3);
}
const seasons_result = seasons_list.map((season_data, season_index) => {
const season_events_sorted = seasons_events[season_index].map(season_data => season_data.event_id).sort();
return {
season_data: season_data,
season_events: {
id_all: season_events_sorted,
id_min: ((season_events_sorted.length > 0) ? season_events_sorted[0] : null),
id_max: ((season_events_sorted.length > 0) ? season_events_sorted[season_events_sorted.length - 1] : null)
}
} as SeasonDataEvents;
});
PreProcess.processed_season_data = seasons_result;
// log
Logger.send_log([
"Completed Event Season Preprocess:",
...seasons_result.map(result_data => `[${result_data.season_data.season_name}] Events: ${result_data.season_events.id_min}~${result_data.season_events.id_max}`)
].join("\n"));
}

}

interface SeasonDataEvents {
season_data: SeasonData,
season_events: {
id_all: number[],
id_min: number,
id_max: number
}
}
130 changes: 103 additions & 27 deletions objects/robotevent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class RobotEvent {
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_TEAMBYNUMBER_${team_number}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const api_response = await this.fetch_retries(`https://www.robotevents.com/api/v2/teams?number=${team_number}&per_page=1000`, 5).then(response => response.json()) as any;
const api_response = await this.fetch_retries(`https://www.robotevents.com/api/v2/teams?number=${team_number}&per_page=250`, 5).then(response => response.json()) as any;
if (api_response.data.length <= 0) return undefined;
const grade_priority = ["College", "High School", "Middle School", "Elementary School"];
const api_team = api_response.data.sort((team_a: any, team_b: any) => grade_priority.indexOf(team_b.grade) - grade_priority.indexOf(team_a.grade))[api_response.data.length - 1];
Expand All @@ -34,7 +34,7 @@ export default class RobotEvent {
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_TEAMAWARDS_${team_id}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`teams/${team_id}/awards?per_page=1000`)).map((award_data: any) => ({
const result = (await this.get_response(`teams/${team_id}/awards?per_page=250`)).map((award_data: any) => ({
award_id: award_data.id,
award_name: award_data.title.match(/^([^\(]+)\s\(/)[1],
award_event: {
Expand All @@ -51,7 +51,7 @@ export default class RobotEvent {
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_TEAMSKILLS_${team_id}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`teams/${team_id}/skills?per_page=1000`)).map((skill_data: any) => ({
const result = (await this.get_response(`teams/${team_id}/skills?per_page=250`)).map((skill_data: any) => ({
skill_id: skill_data.id,
skill_type: skill_data.type,
skill_score: skill_data.score,
Expand All @@ -70,6 +70,65 @@ export default class RobotEvent {
return result;
}

public static async get_seasons(): Promise<SeasonData[]> {
// load cache
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_SEASONDATA_ALL`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`seasons?per_page=250`)).map((season_data: any) => ({
season_id: season_data.id,
season_name: season_data.name,
season_program: {
program_id: season_data.program.id,
program_name: season_data.program.name,
program_code: season_data.program.code,
},
season_date: {
date_begin: season_data.start,
date_end: season_data.end
},
season_year: {
year_begin: season_data.years_start,
year_end: season_data.years_end
}
} as SeasonData));
await VerificationCache.cache_set(`ROBOTEVENT_SEASONDATA_ALL`, result);
return result;
}

public static async get_season_events(season_id: number, season_date_end: number): Promise<EventData[]> {
// load cache
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_SEASONEVENTS_${season_id}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`seasons/${season_id}/events?per_page=250`)).map((event_data: any) => ({
event_id: event_data.id,
event_sku: event_data.sku,
event_name: event_data.name,
event_date: {
date_begin: null as unknown, // disabled as unnecessary/not-used
date_end: null as unknown // disabled as unnecessary/not-used
},
event_program: {
program_id: event_data.program.id,
program_name: event_data.program.name
},
event_location: {
address_lines: [event_data.location.address_1, event_data.location.address_2].filter(address_line => address_line != null),
address_city: event_data.location.city,
address_state: event_data.location.region,
address_postcode: event_data.location.postcode,
address_country: event_data.location.country,
address_latitude: event_data.location.coordinates.lat,
address_longitude: event_data.location.coordinates.lon
}
} as EventData));
// cache for 100 years if season ended (older than 6 months)
const season_ended = (Date.now() - season_date_end) > (6 * 2.592E9);
await VerificationCache.cache_set(`ROBOTEVENT_SEASONEVENTS_${season_id}`, result, (season_ended ? (100 * 3.1536E10) : undefined));
return result;
}

public static async get_season_skills(season_id: number, grade_level: string): Promise<SeasonSkills[]> {
// load cache
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_SEASONSKILLS_${season_id}`);
Expand Down Expand Up @@ -107,7 +166,7 @@ export default class RobotEvent {
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_EVENTTEAMS_${event_id}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`events/${event_id}/teams?per_page=1000`)).map((team_data: any) => ({
const result = (await this.get_response(`events/${event_id}/teams?per_page=250`)).map((team_data: any) => ({
team_id: team_data.id,
team_number: team_data.number,
team_name: team_data.team_name,
Expand All @@ -125,7 +184,7 @@ export default class RobotEvent {
const api_cache = await VerificationCache.cache_get(`ROBOTEVENT_GUILDEVENTS_${guild_id}`);
if (api_cache !== undefined) return api_cache.cache_data;
// cache not exist
const result = (await this.get_response(`events?${team_ids.map(team_id => `team[]=${team_id}`).join("&")}&start=${event_after.toISOString()}&per_page=1000`)).map((event_data: any) => {
const result = (await this.get_response(`events?${team_ids.map(team_id => `team[]=${team_id}`).join("&")}&start=${event_after.toISOString()}&per_page=250`)).map((event_data: any) => {
const event_timezone = VerificationTimezone.timezone_get(event_data.location.coordinates.lat, event_data.location.coordinates.lon);
return {
event_id: event_data.id,
Expand Down Expand Up @@ -209,18 +268,45 @@ export interface EventData {
date_begin: number,
date_end: number
},
event_program: {
program_id: number,
program_name: string
},
event_program: ProgramData,
event_location: LocationData
}

export interface SeasonData {
export interface SeasonDataSimplified {
season_id: number,
season_name: string
}

export interface SeasonData {
season_id: number,
season_name: string,
season_program: ProgramData,
season_date: {
date_begin: number,
date_end: number
},
season_year: {
year_begin: number
year_end: number
}
}

export interface SeasonSkills {
skills_rank: number,
skills_entries: number,
skills_team: TeamData,
skills_score: {
// driver
driver_score: number,
driver_time_stop: number,
driver_score_date: number,
// programming
programming_score: number,
programming_time_stop: number,
programming_score_date: number
}
}

export interface LocationData {
address_lines: string[],
address_city: string,
Expand All @@ -231,6 +317,12 @@ export interface LocationData {
address_longitude: number
}

export interface ProgramData {
program_id: number,
program_name: string,
program_code: string
}

export interface TeamAward {
award_id: number,
award_name: string,
Expand All @@ -244,21 +336,5 @@ export interface TeamSkills {
skill_rank: number,
skill_attempts: number,
skill_event: EventDataSimplified,
skill_season: SeasonData
}

export interface SeasonSkills {
skills_rank: number,
skills_entries: number,
skills_team: TeamData,
skills_score: {
// driver
driver_score: number,
driver_time_stop: number,
driver_score_date: number,
// programming
programming_score: number,
programming_time_stop: number,
programming_score_date: number
}
skill_season: SeasonDataSimplified
}
7 changes: 7 additions & 0 deletions utilities/async_delay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default class AsyncDelay {

public static async async_delay(await_milliseconds: number): Promise<void> {
await new Promise((resolve, reject) => setTimeout(resolve, await_milliseconds));
}

}

0 comments on commit 72a4e75

Please sign in to comment.