1
0
forked from noxious/server

Improved folder structures for better maintainability

This commit is contained in:
2024-07-21 20:20:06 +02:00
parent 88820178cf
commit 62b9b4ec5c
50 changed files with 24 additions and 29 deletions

17
src/utilities/Config.ts Normal file
View File

@ -0,0 +1,17 @@
import dotenv from "dotenv";
dotenv.config();
class config
{
static ENV: string = process.env.ENV || "prod";
static HOST: string = process.env.HOST || "0.0.0.0";
static PORT: number = process.env.PORT ? parseInt(process.env.PORT) : 6969;
static JWT_SECRET: string = process.env.JWT_SECRET || "secret";
static DEFAULT_CHARACTER_ZONE: number = parseInt(process.env.DEFAULT_CHARACTER_ZONE || "1");
static DEFAULT_CHARACTER_X: number = parseInt(process.env.DEFAULT_CHARACTER_POS_X || "0");
static DEFAULT_CHARACTER_Y: number = parseInt(process.env.DEFAULT_CHARACTER_POS_Y || "0");
}
export default config;

103
src/utilities/Http.ts Normal file
View File

@ -0,0 +1,103 @@
/**
* Resources:
* https://stackoverflow.com/questions/76131891/what-is-the-best-method-for-socket-io-authentication
*/
import {Application, Request, Response} from 'express';
import UserService from '../services/UserService';
import jwt from "jsonwebtoken";
import config from "./Config";
import {loginAccountSchema, registerAccountSchema} from "./ZodTypes";
import path from "path";
import { TAsset } from './Types'
import tileRepository from '../repositories/TileRepository'
import objectRepository from '../repositories/ObjectRepository'
import spriteRepository from '../repositories/SpriteRepository'
async function addHttpRoutes(app: Application) {
app.get('/assets', async (req: Request, res: Response) => {
let assets: TAsset[] = [];
const tiles = await tileRepository.getAll();
tiles.forEach(tile => {
assets.push({
key: tile.id,
value: '/assets/tiles/' + tile.id + '.png',
group: 'tiles',
type: 'link'
});
});
const objects = await objectRepository.getAll();
objects.forEach(object => {
assets.push({
key: object.id,
value: '/assets/objects/' + object.id + '.png',
group: 'objects',
type: 'link'
});
});
res.json(assets);
});
app.get('/assets/:type/:file', (req: Request, res: Response) => {
const assetName = req.params.file;
// if (!isValidAsset(assetName)) {
// return res.status(400).send('Invalid asset name');
// }
const options = {
root: path.join(process.cwd(), 'public', req.params.type),
};
res.sendFile(assetName, options, (err) => {
if (err) {
console.error('Error sending file:', err);
res.status(500).send('Error downloading the asset');
}
});
});
app.post('/login', async (req: Request, res: Response) => {
const { username, password } = req.body;
try {
loginAccountSchema.parse({ username, password });
} catch (error: any) {
return res.status(400).json({ message: error.errors[0].message });
}
const userService = new UserService();
const user = await userService.login(username, password);
if (user) { //test
const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' });
return res.status(200).json({ token });
}
return res.status(400).json({ message: 'Failed to login' });
});
app.post('/register', async (req: Request, res: Response) => {
const { username, password } = req.body;
try {
registerAccountSchema.parse({ username, password });
} catch (error: any) {
return res.status(400).json({ message: error.errors[0].message });
}
const userService = new UserService();
const user = await userService.register(username, password);
if (user) {
const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' });
return res.status(200).json({ token });
}
return res.status(400).json({ message: 'Failed to register user' });
});
console.log('[✅] Web routes added');
}
export { addHttpRoutes };

5
src/utilities/Prisma.ts Normal file
View File

@ -0,0 +1,5 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default prisma;

33
src/utilities/Types.ts Normal file
View File

@ -0,0 +1,33 @@
import { Socket } from 'socket.io';
import {Character, User} from "@prisma/client";
export type TSocket = Socket & {
user?: User
character?: Character
handshake?: {
query?: {
token?: any
}
}
request?: {
headers?: {
cookie?: any
}
}
}
export type TCharacter = Socket & {
user?: User,
character?: Character
}
export type TZoneCharacter = Character & {
}
export type TAsset = {
key: string
value: string
group: 'tiles' | 'objects' | 'sound' | 'music' | 'ui' | 'font' | 'other'
type: 'base64' | 'link'
}

28
src/utilities/ZodTypes.ts Normal file
View File

@ -0,0 +1,28 @@
import { z } from 'zod';
export const loginAccountSchema = z.object({
username:z.string()
.min(3, { message: 'Name must be at least 3 characters long' })
.max(255, { message: 'Name must be at most 255 characters long' })
.regex(/^[A-Za-z][A-Za-z0-9_-]*$/, { message: 'Name must start with a letter and can only contain letters, numbers, underscores, or dashes' }),
password: z.string().min(8, {
message: 'Password must be at least 8 characters long'
}).max(255)
});
export const registerAccountSchema = z.object({
username: z.string()
.min(3, { message: 'Name must be at least 3 characters long' })
.max(255, { message: 'Name must be at most 255 characters long' })
.regex(/^[A-Za-z][A-Za-z0-9_-]*$/, { message: 'Name must start with a letter and can only contain letters, numbers, underscores, or dashes' }),
password: z.string().min(8, {
message: 'Password must be at least 8 characters long'
}).max(255)
});
export const ZCharacterCreate = z.object({
name: z.string()
.min(3, { message: 'Name must be at least 3 characters long' })
.max(255, { message: 'Name must be at most 255 characters long' })
.regex(/^[A-Za-z][A-Za-z0-9_-]*$/, { message: 'Name must start with a letter and can only contain letters, numbers, underscores, or dashes' })
});