Skip to content

Commit 7232d7e

Browse files
fix(botCodeStore): ensure user cannot create a second bot even if they are inactive (#199)
## How does this PR impact the user? User won't be able to have multiple bots in the game. Currently, we create them a second bot if they submit code while they are inactive. ## Description - [x] ensure that we check whether the user already has the bot by reading the fs instead of checking the in-memory `ACTIVE_BOT_STORE` ## Limitations N/A ## Checklist - [x] my PR is focused and contains one holistic change - [ ] I have added screenshots or screen recordings to show the changes
1 parent 3724f0e commit 7232d7e

File tree

1 file changed

+44
-17
lines changed

1 file changed

+44
-17
lines changed

other/botCodeStore.ts

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface BotCode {
1313

1414
export type BotCodes = Record<string, BotCode>;
1515

16-
let STORE: BotCodes = {};
16+
let ACTIVE_BOT_STORE: BotCodes = {};
1717

1818
const botEventEmitter = new EventEmitter();
1919

@@ -23,11 +23,36 @@ type SubmitBotCodeArgs = {
2323
userId: number;
2424
};
2525

26+
function formatBotCodeFilename({ username, id, userId }: { username: string; id: string; userId: number }) {
27+
return `${BOT_CODE_DIR}/${username}-${id}-${userId}.js`;
28+
}
29+
30+
function extractBotMetadataFromFilename(filename: string) {
31+
const username = filename.split("-")[0];
32+
const id = filename.split("-")[1];
33+
const userId = filename.split("-")[2]?.replace(".js", "");
34+
if (!id || !username || !userId) {
35+
throw new Error(`Invalid bot code file: ${filename}`);
36+
}
37+
return { id, username, userId: Number(userId) };
38+
}
39+
40+
async function getFirstUserBotMetadata(userId: number) {
41+
const userBotFiles = await fs.readdir(BOT_CODE_DIR);
42+
for (const file of userBotFiles) {
43+
const { username, id, userId: fileUserId } = extractBotMetadataFromFilename(file);
44+
if (fileUserId === userId) {
45+
return { id, username, userId: fileUserId };
46+
}
47+
}
48+
}
49+
2650
export async function submitBotCode({ code, username, userId }: SubmitBotCodeArgs) {
27-
// ensure each user has only one bot
28-
const id = Object.values(STORE).find(botCode => botCode.username === username)?.id || Math.random().toString(36).substring(5);
51+
const existingBotMetadata = await getFirstUserBotMetadata(userId);
52+
// Ensure that every user has only one bot
53+
const id = existingBotMetadata?.id || Math.random().toString(36).substring(5);
2954
const botCode = { id, code, username, userId };
30-
STORE[id] = botCode;
55+
ACTIVE_BOT_STORE[id] = botCode;
3156
await saveBot(botCode);
3257

3358
// Submitting code makes the user active
@@ -36,15 +61,15 @@ export async function submitBotCode({ code, username, userId }: SubmitBotCodeArg
3661
data: { inactive: false },
3762
});
3863

39-
botEventEmitter.emit("update", STORE);
64+
botEventEmitter.emit("update", ACTIVE_BOT_STORE);
4065
}
4166

4267
export function clearBots() {
43-
STORE = {};
68+
ACTIVE_BOT_STORE = {};
4469
}
4570

4671
export function getBots() {
47-
return { ...STORE };
72+
return { ...ACTIVE_BOT_STORE };
4873
}
4974

5075
export function subscribeToBotsUpdate(onUpdate: (bots: BotCodes) => void): () => void {
@@ -75,34 +100,36 @@ async function loadBots() {
75100
const inactiveUserIds = new Set(inactiveUsers.map(user => user.id));
76101

77102
for (const file of files) {
78-
const code = await fs.readFile(`${BOT_CODE_DIR}/${file}`, "utf8");
79-
const username = file.split("-")[0];
80-
const id = file.split("-")[1];
81-
const userId = file.split("-")[2]?.replace(".js", "");
82-
if (!id || !code || !username || !userId) {
103+
const { username, id, userId } = extractBotMetadataFromFilename(file);
104+
if (!id || !username || !userId) {
83105
throw new Error(`Invalid bot code file: ${file}`);
84106
}
85107

86-
if (inactiveUserIds.has(+userId)) {
108+
if (inactiveUserIds.has(userId)) {
87109
continue;
88110
}
89111

90-
STORE[id] = { id, code, username, userId: +userId };
112+
const code = await fs.readFile(`${BOT_CODE_DIR}/${file}`, "utf8");
113+
if (!code) {
114+
throw new Error(`Failed to read bot code file: ${file}`);
115+
}
116+
117+
ACTIVE_BOT_STORE[id] = { id, code, username, userId };
91118
}
92119

93-
botEventEmitter.emit("update", STORE);
120+
botEventEmitter.emit("update", ACTIVE_BOT_STORE);
94121
}
95122

96123
async function saveBot({ id, code, username, userId }: BotCode) {
97124
if (!await fsExists(BOT_CODE_DIR)) {
98125
await fs.mkdir(BOT_CODE_DIR);
99126
}
100-
const botCodeFile = `${BOT_CODE_DIR}/${username}-${id}-${userId}.js`;
127+
const botCodeFile = formatBotCodeFilename({ username, id, userId });
101128

102129
await fs.writeFile(botCodeFile, code);
103130
}
104131

105132
loadBots()
106133
.then(() => {
107-
console.log(`Loaded ${Object.keys(STORE).length} bots`);
134+
console.log(`Loaded ${Object.keys(ACTIVE_BOT_STORE).length} bots`);
108135
});

0 commit comments

Comments
 (0)