Skip to content

Commit

Permalink
Merge pull request #3 from BuidlGuidl/staging
Browse files Browse the repository at this point in the history
Staging
  • Loading branch information
ZakGriffith authored Feb 8, 2024
2 parents e44f11d + d708e7f commit 88b170e
Show file tree
Hide file tree
Showing 63 changed files with 3,650 additions and 285 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged --verbose
# yarn lint-staged --verbose
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"workspaces": {
"packages": [
"packages/hardhat",
"packages/nextjs"
"packages/nextjs",
"packages/backend"
]
},
"scripts": {
Expand All @@ -27,7 +28,8 @@
"postinstall": "husky install",
"precommit": "lint-staged",
"vercel": "yarn workspace @se-2/nextjs vercel",
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo"
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo",
"backend": "yarn workspace @se-2/backend backend"
},
"packageManager": "[email protected]",
"devDependencies": {
Expand Down
Empty file added packages/backend/.env.example
Empty file.
4 changes: 4 additions & 0 deletions packages/backend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# folders
node_modules/
# files
**/*.json
17 changes: 17 additions & 0 deletions packages/backend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"env": {
"node": true
},
"parser": "@typescript-eslint/parser",
"extends": ["plugin:prettier/recommended", "plugin:@typescript-eslint/recommended"],
"rules": {
"@typescript-eslint/no-unused-vars": ["error"],
"@typescript-eslint/no-explicit-any": ["off"],
"prettier/prettier": [
"warn",
{
"endOfLine": "auto"
}
]
}
}
9 changes: 9 additions & 0 deletions packages/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
.env
coverage
coverage.json
typechain
typechain-types
temp


19 changes: 19 additions & 0 deletions packages/backend/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"arrowParens": "avoid",
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "all",
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": true,
"singleQuote": false,
"bracketSpacing": true,
"explicitTypes": "always"
}
}
]
}
3 changes: 3 additions & 0 deletions packages/backend/backend.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const JWT_SECRET = "superhardstring";
export const PORT = 4001;
export const KEY = "";
239 changes: 239 additions & 0 deletions packages/backend/controllers/Admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import Game from "../models/Game";
import Invites from "../models/Invites";
import bcrypt from "bcrypt";
import { Request, Response } from "express";
import jwt from "jsonwebtoken";
import { JWT_SECRET } from "../backend.config";
import { ably } from "..";

async function generateUniqueInvite(length: number) {
let invites = await Invites.findOne();

if (!invites) {
const newInvites = new Invites({
codes: [],
});
invites = await newInvites.save();
}

const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let invite = "";
const existingCodes = invites?.codes || [];

while (true) {
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
invite += characters.charAt(randomIndex);
}

if (!existingCodes.includes(invite)) {
existingCodes.push(invite);
await Invites.findByIdAndUpdate(invites?.id, {
codes: existingCodes,
});
return invite;
}

invite = "";
}
}

export const createGame = async (req: Request, res: Response) => {
try {
const { maxPlayers, diceCount, hiddenChars, privateKey, prize, mode, adminAddress } = req.body;

const salt = await bcrypt.genSalt();
// const privateKeyHash = await bcrypt.hash(privateKey, salt);

const newGame = new Game({
adminAddress,
status: "ongoing",
inviteCode: await generateUniqueInvite(8),
maxPlayers,
diceCount,
mode,
privateKey,
hiddenChars,
prize,
});

let token;

if (JWT_SECRET) token = jwt.sign({ address: adminAddress }, JWT_SECRET);

const savedGame = await newGame.save();
res.status(201).json({ token, game: savedGame });
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const pauseGame = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const game = await Game.findById(id);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status !== "ongoing") {
return res.status(400).json({ error: "Game is not ongoing." });
}

// Update game status to "paused"
game.status = "paused";
const updatedGame = await game.save();

const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, updatedGame);
res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const resumeGame = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const game = await Game.findById(id);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status === "finished") {
return res.status(400).json({ error: "Game has ended." });
}

if (game.status !== "paused") {
return res.status(400).json({ error: "Game is not paused." });
}

// Update game status to "ongoing"
game.status = "ongoing";
const updatedGame = await game.save();

const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, updatedGame);
res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const endGame = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const game = await Game.findById(id);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status === "finished") {
return res.status(400).json({ error: "Game is already finished." });
}

// Update game status to "finished"
game.status = "finished";
if (req.body) {
const { winner } = req.body;
game.winner = winner;
}
const updatedGame = await game.save();

const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, updatedGame);

res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const changeGameMode = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const { mode } = req.body;

const game = await Game.findById(id);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

// if (game.status !== "paused") {
// return res.status(400).json({ error: "Game is not paused." });
// }

if (mode !== "auto" && mode !== "manual") {
return res.status(400).json({ error: "Invalid game mode." });
}

game.mode = mode;

const updatedGame = await game.save();

const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, updatedGame);

res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const changePrize = async (req: Request, res: Response) => {
try {
const { gameId } = req.params;
const { newPrize } = req.body;

const game = await Game.findById(gameId);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status !== "ongoing") {
return res.status(400).json({ error: "Game is not ongoing." });
}

game.prize = newPrize;
const updatedGame = await game.save();

res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const kickPlayer = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const { playerAddress } = req.body;
const game = await Game.findById(id);

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status !== "ongoing") {
return res.status(400).json({ error: "Game is not ongoing." });
}

const playerIndex = game.players.indexOf(playerAddress);
if (playerIndex === -1) {
return res.status(404).json({ error: "Player not found in the game." });
}

game.players.splice(playerIndex, 1);
const updatedGame = await game.save();
const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, updatedGame);

res.status(200).json(updatedGame);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};
47 changes: 47 additions & 0 deletions packages/backend/controllers/Player.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Game from "../models/Game";
import { Response, Request } from "express";
import jwt from "jsonwebtoken";
import { ably } from "..";

const JWT_SECRET = process.env.JWT_SECRET || "superhardstring";

export const join = async (req: Request, res: Response) => {
try {
const { inviteCode, playerAddress } = req.body;
const game = await Game.findOne({ inviteCode });

if (!game) {
return res.status(404).json({ error: "Game not found." });
}

if (game.status !== "ongoing") {
return res.status(400).json({ error: "Game is not ongoing." });
}

if (game.players.length >= game.maxPlayers) {
return res.status(400).json({ error: "Game is full." });
}

if (game.players.includes(playerAddress)) {
return res.status(200).json(game); // Player is already in the game
}

let token;

if (JWT_SECRET) token = jwt.sign({ address: playerAddress }, JWT_SECRET);

game.players.push(playerAddress);
const savedGame = await game.save();

const channel = ably.channels.get(`gameUpdate`);
channel.publish(`gameUpdate`, savedGame);
res.status(200).json({ token, game: savedGame });
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
};

export const leave = () => {};

export const sweepPrize = () => {};
export const markSlotsAsFoundPerPlayer = () => {};
Loading

0 comments on commit 88b170e

Please sign in to comment.