Skip to content

Commit

Permalink
Feat/events support (#36)
Browse files Browse the repository at this point in the history
* add events support
  • Loading branch information
LuisMayo authored Oct 1, 2023
1 parent 320024c commit e1441e4
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 41 deletions.
10 changes: 10 additions & 0 deletions data/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ <h3>Impersonate user</h3>
<button type="submit">Submit</button>
</form>
</div>
<div>
<h3></h3>
<form action="/vhs-admin/change-event" method="post">
<label for="event">Event:</label>
<select id="event" name="event">
${events}
</select>
<button type="submit">Submit</button>
</form>
</div>
<div style="overflow-y: auto;">
${log}
</div>
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"homepage": "https://github.com/LuisMayo/vhs-alternative-server#readme",
"dependencies": {
"@seald-io/nedb": "^4.0.2",
"deepmerge": "^4.3.1",
"express": "^4.18.2",
"express-basic-auth": "^1.2.1",
"jsonwebtoken": "^9.0.2",
Expand Down
26 changes: 24 additions & 2 deletions src/classes/admin-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Request, Response } from "express";
import { Collections } from "./database";
import { DBConstants } from "./constants";
import { Logger } from "./logger";
import { SeasonalEvents } from "../types/save-game";
import { ServerInfo } from "../types/server-info";
import { db } from "..";
import { readFile } from "fs/promises";

Expand All @@ -12,8 +14,9 @@ export class AdminHandler {
let html = await readFile("./data/frontend/index.html", {
encoding: "utf-8",
});
html = html.replace("${lastMessage}", msg ?? '');
html = html.replace("${log}", Logger.getLogListHtml());
html = html.replace("${lastMessage}", msg ?? '')
.replace("${log}", Logger.getLogListHtml())
.replace("${events}", await AdminHandler.getEventsSelect());
response.send(html);
}

Expand Down Expand Up @@ -45,7 +48,26 @@ export class AdminHandler {
}
}


static async updateEvent(req: Request, response: Response) {
if (req.body.event) {
await db.collection(Collections.SERVER_INFO).updateAsync({}, {$set: {currentEvent: req.body.event}});
AdminHandler.adminDashboard(req, response, 'Event set');
} else {
AdminHandler.adminDashboard(req, response, 'Event empty');
}
}

static getImpersonatedId(id: string) {
return AdminHandler.impersonationInfo.get(id) ?? id;
}

private static async getEventsSelect() {
const currentEvent = (await db.collection<ServerInfo>(Collections.SERVER_INFO).findOneAsync({})).currentEvent;
let html = '';
for (const event of Object.values(SeasonalEvents)) {
html += `<option value="${event}" ${currentEvent === event ? 'selected' : ''}>${event}</option>\n`
}
return html;
}
}
12 changes: 9 additions & 3 deletions src/classes/database.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DBConstants } from "./constants";
import Datastore from "@seald-io/nedb";
import { Logger } from "./logger";
import { SeasonalEvents } from "../types/save-game";
import { ServerInfo } from "../types/server-info";
import crypto from 'crypto';
import { readFile } from "fs/promises";
Expand Down Expand Up @@ -54,7 +55,7 @@ export class Database {

private async postInitHook() {
this.initBaseSavegame().then();
this.initJWTSecurity().then();
this.initSettings().then();
}

private async initBaseSavegame() {
Expand All @@ -75,16 +76,21 @@ export class Database {
}
}

private async initJWTSecurity() {
private async initSettings() {
const collection = this.collection<ServerInfo>(Collections.SERVER_INFO);
let settings = await collection.findOneAsync({});
if (settings == null) {
Logger.log('Generating new JWT secret');
settings = {
JWT_SECRET: crypto.randomBytes(64).toString('hex')
JWT_SECRET: crypto.randomBytes(64).toString('hex'),
currentEvent: SeasonalEvents.SET_NoSeasonalEvent,
}
collection.insertAsync(settings).catch(Logger.log);
}
this.token = settings.JWT_SECRET;

if (!settings.currentEvent) {
await collection.updateAsync({}, {$set: {currentEvent: SeasonalEvents.SET_NoSeasonalEvent}});
}
}
}
20 changes: 15 additions & 5 deletions src/classes/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ import { Collections } from "./database";
import { DBConstants } from "./constants";
import { Document } from "@seald-io/nedb";
import { Logger } from "./logger";
import { User } from "../database/database.interface";
import { ServerInfo } from "../types/server-info";
import { User } from "../types/user";
import { db } from "..";
import deepmerge from 'deepmerge';
import jwt_to_pem from 'jwk-to-pem';
import randomstring from "randomstring";
import { readFile } from 'fs/promises';

type DiscoverResponse = SaveGameResponse | MathmakingInfoResponse;

Expand Down Expand Up @@ -89,7 +90,7 @@ export class Handler {
}
const epicId = parsedToken.sub;
const currentTime = Date.now() / 1000;
if (!epicId || !parsedToken.exp || parsedToken.exp < currentTime || !parsedToken.iat || parsedToken.iat > currentTime) {
if (!epicId || !parsedToken.exp || parsedToken.exp < currentTime) {
Logger.log('Ilegal token');
return response.status(401).send("Token malformed");
}
Expand Down Expand Up @@ -135,8 +136,8 @@ export class Handler {
console.error("Unknown discover type", request.body.bitsToDiscover);
case DiscoverTypes.INITIAL_LOAD:
try {
const userSaveGame = await Handler.getUserSaveGame(id);
return response.send(userSaveGame);
const [userSaveGame, serverInfo] = await Promise.all([Handler.getUserSaveGame(id), Handler.getGeneralServerInfo()]);
return response.send(deepmerge(userSaveGame, serverInfo));
} catch (e) {
const str = String(e);
response.status(500).send(str);
Expand Down Expand Up @@ -369,4 +370,13 @@ export class Handler {
}
return userSaveGame;
}

/**
* Get info that's general for the whole server, not of an specific user
* */
static async getGeneralServerInfo(): Promise<Partial<SaveGameResponse>> {
const collection = db.collection<ServerInfo>(Collections.SERVER_INFO);
const event = (await collection.findOneAsync({})).currentEvent;
return {data: {DDT_SeasonalEventBit: {activeSeasonalEventTypes: [event]}}}
}
}
8 changes: 0 additions & 8 deletions src/database/database.interface.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/database/in-memory-database.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ function initServer() {
adminRouter.post("/impersonate-user", (req, res) =>
Handler.wrapper(req, res, AdminHandler.impersonateUser)
);
adminRouter.post("/change-event", (req, res) =>
Handler.wrapper(req, res, AdminHandler.updateEvent)
);
app.use(
"/vhs-admin",
basicAuth({
Expand Down
28 changes: 20 additions & 8 deletions src/types/save-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ enum State {
Disconnected = "disconnected",
}


interface DDTAllInventoryItemsBit {
item?: string;
ctf?: Ctf;
Expand All @@ -336,7 +335,9 @@ enum Ctf {

interface DDTAllLoadoutsBit {
/**Experience, level, matchmaking info and equipment */
characterLoadouts: { [key in Monsters]: CharacterLoadoutsCTEvil } & { [key in Teens]: CharacterLoadoutsCTTeen };
characterLoadouts: { [key in Monsters]: CharacterLoadoutsCTEvil } & {
[key in Teens]: CharacterLoadoutsCTTeen;
};
/**Teen Perk Affinities for point discounts */
teenAffinities: TeenAffinities;
/**For each level how much exp it costs to level UP */
Expand All @@ -348,7 +349,7 @@ export enum Monsters {
WART = "CT_Toad",
Werewolf = "CT_Werewolf",
Deathwire = "CT_Eradicator",
Anomlay = "CT_Anomaly"
Anomlay = "CT_Anomaly",
}

export enum Teens {
Expand All @@ -360,7 +361,6 @@ export enum Teens {
Reggie = "CT_Nerd",
}


export interface CharacterLoadoutsCTEvil {
/**Points, level, etc. And Matchmaking Rank */
points: EvilPoints;
Expand Down Expand Up @@ -1244,7 +1244,7 @@ interface DDMvLtdTwoFeetUnderStdS06 {
rewards?: string[];
}

interface DDMVLTDTWOFEETUNDERSTDS06RequiredEvents { }
interface DDMVLTDTWOFEETUNDERSTDS06RequiredEvents {}

interface DDMVLTDTWOFEETUNDERSTDS07Class {
sceneData?: SceneData;
Expand Down Expand Up @@ -10054,8 +10054,10 @@ interface PurchaseOptionsThirdParty {
}

interface DDTAllWeaponsBit {
weaponLoadoutsByCharacterType?: { [key in Teens]: WeaponLoadoutsByCharacterTypeCTTeen } & {
CT_DollMaster?: WeaponLoadoutsByCharacterTypeCTDollMaster,
weaponLoadoutsByCharacterType?: {
[key in Teens]: WeaponLoadoutsByCharacterTypeCTTeen;
} & {
CT_DollMaster?: WeaponLoadoutsByCharacterTypeCTDollMaster;
CT_Toad?: CTToad;
CT_Werewolf?: CTWerewolf;
CT_Eradicator?: WeaponLoadoutsByCharacterTypeCTEradicator;
Expand Down Expand Up @@ -10445,9 +10447,19 @@ interface JourneysByJourneyKeyCTCheerleader {
"1": { [key: string]: { [key: string]: boolean } };
}

export enum SeasonalEvents {
SET_NoSeasonalEvent = "SET_NoSeasonalEvent",
SET_Halloween = "SET_Halloween",
SET_Holiday = "SET_Holiday",
SET_Valentines = "SET_Valentines",
SET_Easter = "SET_Easter",
SET_Max = "SET_Max",
SET_DoubleXP = "SET_DoubleXP",
}

/**Server Details about current seasonal event */
interface DDTSeasonalEventBit {
activeSeasonalEventTypes?: string[];
activeSeasonalEventTypes: SeasonalEvents[];
}

interface DDTServerNotificationBit {
Expand Down
3 changes: 3 additions & 0 deletions src/types/server-info.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { SeasonalEvents } from "./save-game";

export type ServerInfo = {
JWT_SECRET: string;
currentEvent: SeasonalEvents;
}
5 changes: 5 additions & 0 deletions src/types/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface User {
epicId: string;
displayName: string;
}

0 comments on commit e1441e4

Please sign in to comment.