Skip to content

Commit

Permalink
feat(app): create "RedemptionType" enum and load actions from json file
Browse files Browse the repository at this point in the history
use the created enum instead of the id on the frontend and store the mapping on a json file
  • Loading branch information
alexbcberio committed Oct 18, 2022
1 parent 42dd5e4 commit 0379f04
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 44 deletions.
Empty file added config/.gitkeep
Empty file.
87 changes: 57 additions & 30 deletions src/backend/pubSubClient/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PubSubClient, PubSubRedemptionMessage } from "@twurple/pubsub";
import { access, readFile } from "fs/promises";
import {
cancelRewards,
completeRewards,
Expand All @@ -15,10 +16,12 @@ import {
timeoutFriend,
} from "./actions";

import { RedemptionIds } from "../../enums/Redemptions";
import { RedemptionMessage } from "../../interfaces/RedemptionMessage";
import { RedemptionType } from "../../enums/RedemptionType";
import { UserIdResolvable } from "@twurple/api";
import { broadcast } from "../webserver";
import { constants } from "fs";
import { cwd } from "process";
import { isProduction } from "../helpers/util";
import { rawDataSymbol } from "@twurple/common";

Expand All @@ -27,38 +30,63 @@ const log = extendLogger(namespace);

type RedemptionHandler = (msg: RedemptionMessage) => Promise<RedemptionMessage>;

function getRedemptionHandlerFromRewardId(rewardId: string): RedemptionHandler {
const noop = (message: RedemptionMessage): Promise<RedemptionMessage> => {
log("Unhandled redemption %s", rewardId);
return Promise.resolve(message);
};
const configFilePath = `${cwd()}/config/redemptions.json`;

let redemptions: Record<string, RedemptionType> = {};

switch (rewardId) {
case RedemptionIds.GetVip:
async function loadRedemptions() {
try {
await access(configFilePath, constants.R_OK);
} catch (e) {
error(
'[%s] Cannot access configuration file "%s"',
namespace,
configFilePath
);
return;
}

const redemptionsConfig = await readFile(configFilePath);

try {
redemptions = JSON.parse(redemptionsConfig.toString());
} catch (e) {
error(
'[%s] Error parsing configuration file "%s"',
namespace,
configFilePath
);
}
}

function noop(message: RedemptionMessage): Promise<RedemptionMessage> {
log("Unhandled redemption %s", message.rewardId);
return Promise.resolve(message);
}

function getRedemptionHandlerFromRewardId(rewardId: string): RedemptionHandler {
switch (redemptions[rewardId]) {
case RedemptionType.GetVip:
return getVip;
case RedemptionIds.Hidrate:
case RedemptionType.Hidrate:
return hidrate;
case RedemptionIds.HighlightMessage:
case RedemptionType.HighlightMessage:
return highlightMessage;
case RedemptionIds.LightTheme2m:
case RedemptionIds.LightTheme5m:
case RedemptionType.LightTheme:
return lightTheme;
case RedemptionIds.RussianRoulette:
case RedemptionType.RussianRoulette:
return russianRoulette;
case RedemptionIds.StealVip:
case RedemptionType.StealVip:
return stealVip;
case RedemptionIds.TimeoutFriend:
case RedemptionType.TimeoutFriend:
return timeoutFriend;
default:
return noop;
}
}

function keepInQueue(rewardId: string): boolean {
const keepInQueueRewards = [RedemptionIds.KaraokeTime];

// @ts-expect-error String is not assignable to... but all keys are strings
if (keepInQueueRewards.includes(rewardId)) {
if (redemptions[rewardId] === RedemptionType.KaraokeTime) {
return true;
}

Expand Down Expand Up @@ -107,16 +135,17 @@ async function completeReward(message: PubSubRedemptionMessage): Promise<void> {
}
}

function rewardNameFromRewardId(rewardId: string): string {
const rewardEnumValues = Object.values(RedemptionIds);
// @ts-expect-error String is not assignable to... but all keys are strings
const rewardIdValueIndex = rewardEnumValues.indexOf(rewardId);
const rewardName = Object.keys(RedemptionIds)[rewardIdValueIndex];

return rewardName;
function rewardTypeFromRewardId(rewardId: string): RedemptionType {
return redemptions[rewardId];
}

async function onRedemption(message: PubSubRedemptionMessage) {
// eslint-disable-next-line no-magic-numbers
if (Object.keys(redemptions).length === 0) {
log("Loading redemptions");
await loadRedemptions();
}

log(
'Reward: "%s" (%s) redeemed by %s',
message.rewardTitle,
Expand All @@ -130,6 +159,7 @@ async function onRedemption(message: PubSubRedemptionMessage) {
id: message.id,
channelId: message.channelId,
rewardId: message.rewardId,
rewardType: rewardTypeFromRewardId(message.rewardId),
rewardName: message.rewardTitle,
rewardImage: message.rewardImage
? message.rewardImage.url_4x
Expand All @@ -146,10 +176,7 @@ async function onRedemption(message: PubSubRedemptionMessage) {
const redemptionHandler = getRedemptionHandlerFromRewardId(msg.rewardId);

try {
handledMessage = {
...(await redemptionHandler(msg)),
rewardId: rewardNameFromRewardId(message.rewardId),
};
handledMessage = await redemptionHandler(msg);
} catch (e) {
if (e instanceof Error) {
error("[%s] %s", namespace, e.message);
Expand Down
10 changes: 10 additions & 0 deletions src/enums/RedemptionType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum RedemptionType {
GetVip = "getVip",
Hidrate = "hidrate",
HighlightMessage = "highlightMessage",
KaraokeTime = "karaokeTime",
LightTheme = "lightTheme",
RussianRoulette = "russianRoulette",
StealVip = "stealVip",
TimeoutFriend = "timeoutFriend",
}
11 changes: 0 additions & 11 deletions src/enums/Redemptions.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/interfaces/RedemptionMessage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { RedemptionType } from "../enums/RedemptionType";

export interface RedemptionMessage {
id: string;
channelId: string;
rewardId: string;
rewardType: RedemptionType;
rewardName: string;
rewardImage: string;
rewardCost: number;
Expand Down
9 changes: 6 additions & 3 deletions src/www/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "./events/redemption";

import { RedemptionMessage } from "../../interfaces/RedemptionMessage";
import { RedemptionType } from "../../enums/RedemptionType";
import { Song } from "../../interfaces/Song";
import { sleep } from "./helpers/sleep";

Expand Down Expand Up @@ -49,6 +50,8 @@ async function checkEvent(this: WebSocket, e: MessageEvent) {
const song: Song = message;
updateSong(song);
return;
} else if (!message.rewardId) {
return;
}

events.push(message);
Expand All @@ -71,11 +74,11 @@ async function checkEvent(this: WebSocket, e: MessageEvent) {
}

if (data.channelId) {
switch (data.rewardId) {
case "KaraokeTime":
switch (data.rewardType) {
case RedemptionType.KaraokeTime:
await karaokeTime(data.userDisplayName, data.message);
break;
case "RussianRoulette":
case RedemptionType.RussianRoulette:
await russianRoulette(data);
break;
default:
Expand Down

0 comments on commit 0379f04

Please sign in to comment.