forked from noxious/server
Improved folder structures for better maintainability
This commit is contained in:
17
src/utilities/Config.ts
Normal file
17
src/utilities/Config.ts
Normal 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
103
src/utilities/Http.ts
Normal 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
5
src/utilities/Prisma.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default prisma;
|
33
src/utilities/Types.ts
Normal file
33
src/utilities/Types.ts
Normal 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
28
src/utilities/ZodTypes.ts
Normal 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' })
|
||||
});
|
Reference in New Issue
Block a user