Skip to content

Commit

Permalink
Finish map and series flows.
Browse files Browse the repository at this point in the history
Update github actions to deploy next and version tag.

Begin work on demo uploads.
  • Loading branch information
PhlexPlexico committed Jun 16, 2023
1 parent 72e205e commit cffb4e0
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 24 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/ghcr.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
name: publish to ghcr
name: Publish to GHCR
on:
workflow_dispatch:
push:
branches:
- master
- v2-api
jobs:
push:
name: "Create build and push to GHCR"
name: Create build and push to GHCR
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -33,11 +34,12 @@ jobs:
- id: getversion
uses: Saionaro/extract-package-version@v1.2.1
- uses: docker/build-push-action@v3.2.0
if: github.ref == 'refs/heads/master'
with:
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm/v7,linux/arm64/v8
push: true
tags: |
ghcr.io/${{ steps.string.outputs.lowercase }}/g5api:latest,ghcr.io/${{ steps.string.outputs.lowercase }}/g5api:${{ steps.getversion.outputs.version }}
ghcr.io/${{ steps.string.outputs.lowercase }}/g5api:next,ghcr.io/${{ steps.string.outputs.lowercase }}/g5api:${{ steps.getversion.outputs.version }}
5 changes: 4 additions & 1 deletion src/routes/v2/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** Express API router for teams in get5.
/** Express API router for game server updates in get5.
* @module routes/v2
* @requires express
* @requires db
Expand Down Expand Up @@ -36,6 +36,7 @@ import MapFlowService from "../../services/mapflowservices.js";
import { Get5_OnMatchPausedUnpaused } from "../../types/map_flow/Get5_OnMatchPausedUnpaused.js";
import { Get5_OnPlayerDeath } from "../../types/map_flow/Get5_OnPlayerDeath.js";
import { Get5_OnBombEvent } from "../../types/map_flow/Get5_OnBombEvent.js";
import { Get5_OnRoundStart } from "../../types/map_flow/Get5_OnRoundStart.js";

/** Basic Rate limiter.
* @const
Expand Down Expand Up @@ -144,6 +145,8 @@ router.post("/", basicRateLimit, async (req, res) => {
// Map Flows
case "going_live":
MapFlowService.OnGoingLive(apiKey, req.body as Get5_OnGoingLive, res);
case "round_start":
MapFlowService.OnRoundStart(apiKey, req.body as Get5_OnRoundStart, res);
case "player_death":
MapFlowService.OnPlayerDeath(
apiKey,
Expand Down
31 changes: 31 additions & 0 deletions src/routes/v2/demoapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/** Express API router for demo uploads in get5.
* @module routes/v2
* @requires express
* @requires db
*/


/**
* @swagger
* resourcePath: /v2/demo
* description: Express API for v2 API calls in G5API.
*/

/** ZIP files.
* @const
*/
import JSZip from "jszip";

/** Required to save files.
* @const
*/
import { existsSync, mkdirSync, writeFile } from "fs";

/** Config to check demo uploads.
* @const
*/
import config from "config";

import { db } from "../../services/db.js";


188 changes: 170 additions & 18 deletions src/services/mapflowservices.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
import { db } from "./db.js";

/** ZIP files.
* @const
*/
import JSZip from "jszip";

/** Required to save files.
* @const
*/
import { existsSync, mkdirSync, writeFile } from "fs";

/** Config to check demo uploads.
* @const
*/
import config from "config";

/**
* @const
* Global Server Sent Emitter class for real time data.
Expand All @@ -28,6 +13,10 @@ import { RowDataPacket } from "mysql2";
import { Get5_OnMatchPausedUnpaused } from "../types/map_flow/Get5_OnMatchPausedUnpaused.js";
import { Get5_OnPlayerDeath } from "../types/map_flow/Get5_OnPlayerDeath.js";
import { Get5_OnBombEvent } from "../types/map_flow/Get5_OnBombEvent.js";
import { Get5_OnRoundEnd } from "../types/map_flow/Get5_OnRoundEnd.js";
import SeriesFlowService from "./seriesflowservices.js";
import { Get5_OnRoundStart } from "../types/map_flow/Get5_OnRoundStart.js";
import { Get5_Player } from "../types/Get5_Player.js";

class MapFlowService {
static async OnGoingLive(
Expand All @@ -40,7 +29,6 @@ class MapFlowService {
apiKey,
event.matchid
);
// XXX: Figure out where to store version number, be it at match start or when calling get5_status when creating the match.
let sqlString: string;
let mapStatInfo: RowDataPacket[];
let vetoInfo: RowDataPacket[];
Expand Down Expand Up @@ -358,11 +346,12 @@ class MapFlowService {
defused: defused,
bomb_time_remaining: event?.bomb_time_remaining
};

insObject = await db.buildUpdateStatement(insObject);
sqlString = "INSERT INTO match_bomb_plant SET ?";
sqlString = "INSERT INTO match_bomb_plants SET ?";
await db.query(sqlString, insObject);
GlobalEmitter.emit("bombEvent");
res.status(200).send({ message: "Success" });
return;
} catch (error) {
console.error(error);
Expand All @@ -371,6 +360,169 @@ class MapFlowService {
}
}

static async OnRoundEnd(
apiKey: string,
event: Get5_OnRoundEnd,
res: Response
) {
try {
const matchApiCheck: number = await Utils.checkApiKey(
apiKey,
event.matchid
);
let sqlString: string =
"SELECT id FROM map_stats WHERE match_id = ? AND map_number = ?";
let insUpdStatement: object;
let mapStatInfo: RowDataPacket[];
let playerStats: RowDataPacket[];
let singlePlayerStat: RowDataPacket[];
if (matchApiCheck == 2 || matchApiCheck == 1) {
res.status(401).send({
message:
"Match already finalized or and invalid API key has been given."
});
return;
}
mapStatInfo = await db.query(sqlString, [
event.matchid,
event.map_number
]);
sqlString =
"SELECT * FROM player_stats WHERE match_id = ? AND map_id = ?";
playerStats = await db.query(sqlString, [event.matchid, mapStatInfo[0].id]);
for (let player of event.team1.players) {
singlePlayerStat = playerStats.filter(
(dbPlayer) => dbPlayer.steam_id == player.steamid
);
await this.updatePlayerStats(
event,
mapStatInfo[0].id,
player,
singlePlayerStat[0].id
);
}
for (let player of event.team2.players) {
singlePlayerStat = playerStats.filter(
(dbPlayer) => dbPlayer.steam_id == player.steamid
);
await this.updatePlayerStats(
event,
mapStatInfo[0].id,
player,
singlePlayerStat[0].id
);
}
GlobalEmitter.emit("playerStatsUpdate");
res.status(200).send({ message: "Success" });
} catch (error) {
console.error(error);
res.status(500).send({ message: error });
return;
}
}

private static async updatePlayerStats(event: Get5_OnRoundEnd, mapId: number, player: Get5_Player, playerId: number | null) {
let insUpdStatement: object;
let sqlString: string;
insUpdStatement = {
match_id: event.matchid,
map_id: mapId,
team_id: event.team1.id,
steam_id: player.steamid,
name: player.name,
kills: player.stats?.kills,
deaths: player.stats?.deaths,
roundsplayed: player.stats?.rounds_played,
assists: player.stats?.assists,
flashbang_assists: player.stats?.flash_assists,
teamkills: player.stats?.team_kills,
knife_kills: player.stats?.knife_kills,
suicides: player.stats?.suicides,
headshot_kills: player.stats?.headshot_kills,
damage: player.stats?.damage,
util_damage: player.stats?.utility_damage,
enemies_flashed: player.stats?.enemies_flashed,
friendlies_flashed: player.stats?.friendlies_flashed,
bomb_plants: player.stats?.bomb_plants,
bomb_defuses: player.stats?.bomb_defuses,
v1: player.stats?.["1v1"],
v2: player.stats?.["1v2"],
v3: player.stats?.["1v3"],
v4: player.stats?.["1v4"],
v5: player.stats?.["1v5"],
k1: player.stats?.["1k"],
k2: player.stats?.["2k"],
k3: player.stats?.["3k"],
k4: player.stats?.["4k"],
k5: player.stats?.["5k"],
firstdeath_ct: player.stats?.first_deaths_ct,
firstdeath_t: player.stats?.first_deaths_t,
firstkill_ct: player.stats?.first_kills_ct,
firstkill_t: player.stats?.first_kills_t,
kast: player.stats?.kast,
contribution_score: player.stats?.score,
mvp: player.stats?.mvp
};

insUpdStatement = await db.buildUpdateStatement(insUpdStatement);

if (playerId) {
sqlString = "UPDATE player_stats SET ? WHERE id = ?";
await db.query(sqlString, [insUpdStatement, playerId]);
} else {
sqlString = "INSERT INTO player_stats SET ?";
await db.query(sqlString, insUpdStatement);
}
}

static async OnRoundStart(
apiKey: string,
event: Get5_OnRoundStart,
res: Response
) {
const matchApiCheck: number = await Utils.checkApiKey(
apiKey,
event.matchid
);
let sqlString: string;
let mapStatInfo: RowDataPacket[];
if (matchApiCheck == 2 || matchApiCheck == 1) {
res.status(401).send({
message:
"Match already finalized or and invalid API key has been given."
});
// Check if round was backed up and nuke the additional player stats and bomb plants.
if (SeriesFlowService.wasRoundRestored) {
sqlString =
"SELECT id FROM map_stats WHERE match_id = ? AND map_number = ?";
mapStatInfo = await db.query(sqlString, [
event.matchid,
event.map_number
]);

sqlString =
"DELETE FROM match_bomb_plants WHERE round_number > ? AND match_id = ? AND map_id = ?";
await db.query(sqlString, [
event.round_number,
event.matchid,
mapStatInfo[0].id
]);

sqlString =
"DELETE FROM player_stat_extras WHERE match_id = ? AND map_id = ? AND round_number > ?";
await db.query(sqlString, [
event.matchid,
mapStatInfo[0].id,
event.round_number
]);
SeriesFlowService.wasRoundRestored = false;
}
GlobalEmitter.emit("playerStatsUpdate");
res.status(200).send({ message: "Success" });
return;
}
}

static async OnMatchPausedUnPaused(
apiKey: string,
event: Get5_OnMatchPausedUnpaused,
Expand Down
6 changes: 6 additions & 0 deletions src/types/map_flow/Get5_OnRoundStart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Get5_OnRoundStart {
event: string
matchid: string,
map_number: number,
round_number: number
}
4 changes: 2 additions & 2 deletions src/utility/serverrcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ class ServerRcon {

await this.execute(
"get5_demo_upload_url " + config.get("server.apiURL").endsWith("/")
? +"v2"
: +"/v2"
? +"v2/demo"
: +"/v2/demo"
);
await this.execute("get5_demo_upload_header_key Authorization");
await this.execute("get5_demo_upload_header_value " + get5APIKeyString);
Expand Down

0 comments on commit cffb4e0

Please sign in to comment.