1
0
forked from noxious/server

my 13th reason

This commit is contained in:
2024-05-28 21:54:34 +02:00
parent 4157ff5b5c
commit 80ec470fd4
30 changed files with 283 additions and 70 deletions

View File

@ -1,11 +1,11 @@
import {User} from "@prisma/client";
interface ILoggedInUsers {
type TLoggedInUsers = {
users: User[];
}
class UserManager {
private loggedInUsers: ILoggedInUsers[] = [];
private loggedInUsers: TLoggedInUsers[] = [];
// Method to initialize user manager
public async boot() {

View File

@ -1,14 +1,14 @@
import {Character, Zone} from "@prisma/client";
import ZoneRepository from "./repositories/zone.repository";
import ZoneService from "./services/zone.service";
import ZoneRepository from "./repositories/ZoneRepository";
import ZoneService from "./services/ZoneService";
interface ILoadedZone {
type TLoadedZone = {
zone: Zone;
characters: Character[];
}
class ZoneManager {
private loadedZones: ILoadedZone[] = [];
private loadedZones: TLoadedZone[] = [];
// Method to initialize zone manager
public async boot() {

View File

@ -0,0 +1,8 @@
import { Socket, Server } from "socket.io";
import {TSocket} from "../types/TSocket";
export default function CharacterConnect(socket: TSocket, io: Server) {
socket.on('character:connect', (data: any) => {
console.log(`---User ${socket.user?.id} has joined.`);
});
}

View File

@ -1,5 +1,5 @@
import { Socket, Server } from "socket.io";
import ZoneRepository from "../repositories/zone.repository";
import ZoneRepository from "../repositories/ZoneRepository";
import ZoneManager from "../ZoneManager";
import {Zone} from "@prisma/client";
@ -14,7 +14,7 @@ interface IZoneLoad {
* @param socket
* @param io
*/
export default function characterZoneLoad(socket: Socket, io: Server) {
export default function CharacterZoneLoad(socket: Socket, io: Server) {
socket.on('character:zone:load', async (data: IZoneLoad) => {
console.log(`---User ${socket.id} has requested zone.`);

View File

@ -0,0 +1,8 @@
import { Socket, Server } from "socket.io";
import {TSocket} from "../types/TSocket";
export default function CharactersGet(socket: TSocket, io: Server) {
socket.on('characters:get', async (data: any) => {
console.log(socket.user);
});
}

View File

@ -1,7 +1,7 @@
import { Socket, Server } from "socket.io";
export default function user_connect(socket: Socket, io: Server) {
socket.on('disconnect', (data) => {
export default function Disconnect(socket: Socket, io: Server) {
socket.on('disconnect', (data: any) => {
console.log(`---User ${socket.id} has disconnected.`);
});
}

7
src/app/events/Login.ts Normal file
View File

@ -0,0 +1,7 @@
import { Socket, Server } from "socket.io";
export default function Login(socket: Socket, io: Server) {
socket.on('login', (data: any) => {
console.log(`---User ${socket.id} has logged in.`);
});
}

View File

@ -1,9 +0,0 @@
import { Socket, Server } from "socket.io";
import {ISocket} from "../interfaces/socket";
export default function characterConnect(socket: ISocket, io: Server) {
socket.on('character:connect', (data) => {
socket.user.username = 'hello'
console.log(`---User ${socket.id} has joined.`);
});
}

View File

@ -1,9 +0,0 @@
import { Socket, Server } from "socket.io";
import {ISocket} from "../interfaces/socket";
export default function characterConnect(socket: ISocket, io: Server) {
socket.on('characters:get', async (data) => {
console.log(socket.user.username)
console.log(`---characters requested.`);
});
}

17
src/app/index.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import "socket.io";
declare module "socket.io" {
interface Socket {
data: {
user: {
id: string;
username: string;
};
};
handshake: {
headers: {
cookie: string;
};
};
}
}

View File

@ -1,5 +0,0 @@
import {Socket} from "socket.io";
export interface ISocket extends Socket {
user?: any;
}

View File

@ -1,6 +0,0 @@
import {Character} from "@prisma/client";
interface zoneCharacters extends Character
{
}

View File

@ -0,0 +1,37 @@
// socket io jwt auth middleware
import { verify } from 'jsonwebtoken';
import { TSocket } from '../types/TSocket';
import config from "../utilities/Config";
import UserRepository from "../repositories/UserRepository";
import {User} from "@prisma/client";
export async function Authentication (socket: TSocket, next: any) {
if (!socket.request.headers.cookie) {
console.log('No cookie provided');
return next(new Error('Authentication error'));
}
const cookies = socket.request.headers.cookie.split('; ').reduce((prev: any, current: any) => {
const [name, value] = current.split('=');
prev[name] = value;
return prev;
}, {});
const token = cookies['token'];
if (token) {
verify(token, config.JWT_SECRET, async (err: any, decoded: any) => {
if (err) {
console.log('err');
return next(new Error('Authentication error'));
}
socket.user = await UserRepository.getById(decoded.id) as User;
next();
});
} else {
console.log('No token provided');
next(new Error('Authentication error'));
}
}

View File

@ -1,6 +1,6 @@
import prisma from '../utilities/prisma'; // Import the global Prisma instance
import prisma from '../utilities/Prisma'; // Import the global Prisma instance
import {Character} from '@prisma/client';
import CharacterService from "../services/character.service";
import CharacterService from "../services/CharacterService";
class CharacterRepository {
async getByUserId(userId: number): Promise<Character[] | null> {

View File

@ -1,7 +1,19 @@
import prisma from '../utilities/prisma'; // Import the global Prisma instance
import prisma from '../utilities/Prisma'; // Import the global Prisma instance
import { User } from '@prisma/client';
class UserRepository {
async getById(id: number): Promise<User | null> {
try {
return await prisma.user.findUnique({
where: {
id,
},
});
} catch (error: any) {
// Handle error
throw new Error(`Failed to get user by ID: ${error.message}`);
}
}
async getByUsername(username: string): Promise<User | null> {
try {
return await prisma.user.findUnique({
@ -14,7 +26,6 @@ class UserRepository {
throw new Error(`Failed to get user by username: ${error.message}`);
}
}
async create(username: string, password: string): Promise<User> {
try {
return await prisma.user.create({

View File

@ -1,5 +1,5 @@
import { Zone } from '@prisma/client';
import prisma from '../utilities/prisma'; // Import the global Prisma instance
import prisma from '../utilities/Prisma'; // Import the global Prisma instance
class ZoneRepository {
async getFirst(): Promise<Zone | null> {

View File

@ -1,6 +1,6 @@
import bcrypt from "bcryptjs";
import UserRepository from "../repositories/user.repository";
import CharacterRepository from "../repositories/character.repository";
import UserRepository from "../repositories/UserRepository";
import CharacterRepository from "../repositories/CharacterRepository";
class UserService {
async login(username: string, password: string): Promise<boolean | any> {

View File

@ -1,5 +1,5 @@
import {Zone} from "@prisma/client";
import ZoneRepository from "../repositories/zone.repository";
import ZoneRepository from "../repositories/ZoneRepository";
class ZoneService
{

View File

@ -1,8 +1,7 @@
import { Socket } from 'socket.io';
import {Character as ICharacter, User} from "@prisma/client";
interface Character extends Socket
{
export type TCharacter = Socket & {
user?: User,
character?: ICharacter
}

16
src/app/types/TSocket.ts Normal file
View File

@ -0,0 +1,16 @@
import {Socket} from "socket.io";
import { User } from '@prisma/client';
export type TSocket = Socket & {
user?: User
handshake?: {
query?: {
token?: any
}
}
request?: {
headers?: {
cookie?: any
}
}
}

View File

@ -0,0 +1,5 @@
import {Character} from "@prisma/client";
export type TZoneCharacter = Character & {
}

View File

@ -5,6 +5,7 @@ dotenv.config();
class config {
static ENV: string = process.env.ENV || "prod";
static PORT: number = process.env.PORT ? parseInt(process.env.PORT) : 5000;
static JWT_SECRET: string = process.env.JWT_SECRET || "secret";
}
export default config;

View File

@ -1,7 +1,15 @@
import { Request, Response } from 'express';
import UserService from '../services/user.service';
/**
* Resources:
* https://stackoverflow.com/questions/76131891/what-is-the-best-method-for-socket-io-authentication
*
*/
async function addAuthRoutes(app: any) {
import {Application, Request, Response} from 'express';
import UserService from '../services/UserService';
import jwt from "jsonwebtoken";
import config from "./Config";
async function addAuthRoutes(app: Application) {
app.post('/login', async (req: Request, res: Response) => {
const { username, password } = req.body;
@ -9,7 +17,8 @@ async function addAuthRoutes(app: any) {
const user = await userService.login(username, password);
if (user) {
return res.status(200).json(user);
const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' });
return res.status(200).json({ token });
}
return res.status(401).json({ message: 'Invalid credentials' });
});
@ -21,7 +30,8 @@ async function addAuthRoutes(app: any) {
const user = await userService.register(username, password);
if (user) {
return res.status(201).json(user);
const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '1h' });
return res.status(201).json({ token });
}
return res.status(400).json({ message: 'Failed to register user' });
});
@ -29,4 +39,4 @@ async function addAuthRoutes(app: any) {
console.log('[✅] Auth routes added');
}
export default { addAuthRoutes };
export { addAuthRoutes };