add status and elo system, move all containers into containers folder

This commit is contained in:
kinou-p 2023-05-12 16:15:06 +02:00
parent a4f79c56e1
commit 0845fea10f
109 changed files with 439 additions and 369 deletions

11
.gitignore vendored
View File

@ -1,12 +1,15 @@
#.env
backend/node_modules/
backend/dist/
containers/backend/dist/
api/node_modules/
api/dist/
containers/api/dist/
pong/node_modules/
pong/dist/
containers/pong/dist/
*/node_modules/
*/dist/
*/*/node_modules/
*/dist/
*/*/dist/

View File

@ -6,13 +6,13 @@
# By: apommier <apommier@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2023/03/19 09:29:27 by apommier #+# #+# #
# Updated: 2023/04/04 18:14:43 by apommier ### ########.fr #
# Updated: 2023/05/10 13:37:27 by apommier ### ########.fr #
# #
# **************************************************************************** #
all:
# -mkdir -p /home/apommier/data/wordpress
-mkdir -p /home/apommier/data/pgsql
# -mkdir -p /home/apommier/data/pgsql
docker-compose -f docker-compose.yml up --build
fclean: down

View File

@ -1,4 +1,4 @@
import { Controller, Request, Req, Get, Post, UseGuards, Redirect, Res } from '@nestjs/common';
import { Controller, Request, Req, Get, Post, UseGuards, Redirect, Res, Body } from '@nestjs/common';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { AuthService } from './auth/auth.service';
@ -6,6 +6,8 @@ import { loginClass } from './auth/login42'
import { ChatService } from './chat/chat.service';
import { UsersService } from './users/users.service';
import { MatchLog } from './model/user.entity'
// import { AuthGuard } from '@nestjs/passport';
// import { Login42 } from './auth/login42'
// import { loginClass } from './auth/test'
@ -18,11 +20,8 @@ export class AppController {
private chatService: ChatService,
private userService: UsersService, ) {}
// @Post('auth/login')
// async login() {
// const user = Login42();
// return this.authService.login5(user);
// }
kFactor = 36;
scaleFactor = 400;
@Redirect('http://localhost/token', 302)
@Get('auth/login')
@ -39,14 +38,6 @@ export class AppController {
console.log(`data in api = ${(await data).access_token}`)
const token = (await data).access_token;
return { url: `http://localhost/token?data=${encodeURIComponent(JSON.stringify(token))}` };
// console.log("login function");
// console.log(`url = ${url}`);
// const user = this.loginClass.Login42(url);
// console.log("login42 done");
// console.log(`user= ${user}`);
// console.log(`dataaaa = ${data}`);
// console.log("before return");
// return { data };
}
@UseGuards(JwtAuthGuard)
@ -56,40 +47,72 @@ export class AppController {
console.log(`req user api= ${req.user}`)
console.log(`json user api= ${myJSON}`)
return req.user;
// const user = req.user;
// const returned = {
// username: user.username,
// sub: user.sub,
// };
// console.log(`user in api = ${returned}`)
// return returned;
}
@UseGuards(JwtAuthGuard)
@Post('/win')
async addWin(@Request() req) {
async addWin(@Request() req, @Body() data: any) {
const user = await this.userService.findOne(req.user.username);
user.win++;
this.userService.save(user);
const Esp = 1 / (1 + Math.pow(10, (data.opRank - user.rank) / this.scaleFactor))
const newRank = user.rank + this.kFactor * (1 - Esp);
user.rank = newRank;
console.log(`win new rank= ${newRank}`);
console.log(`data win = ${data}`)
const newMatch = new MatchLog;
newMatch.myScore = data.myScore;
newMatch.opScore = data.opScore;
newMatch.opponent = data.opName;
newMatch.parent = user;
await this.userService.saveChild(user, newMatch);
}
@UseGuards(JwtAuthGuard)
@Post('/loss')
async addLoss(@Request() req) {
async addLoss(@Request() req, @Body() data: any) {
const user = await this.userService.findOne(req.user.username);
user.loss++;
this.userService.save(user);
const Esp = 1 / (1 + Math.pow(10, (data.opRank - user.rank) / this.scaleFactor))
const newRank = user.rank + this.kFactor * (0 - Esp);
user.rank = newRank;
console.log(`loss new rank= ${newRank}`);
console.log(`data loss = ${data}`)
const newMatch = new MatchLog;
newMatch.myScore = data.myScore;
newMatch.opScore = data.opScore;
newMatch.opponent = data.opName;
newMatch.parent = user;
await this.userService.saveChild(user, newMatch);
}
// @UseGuards(JwtAuthGuard)
// @Post('/api/victory')
// addVictory() {
// this.userService.findOneBy()
// }
@Get('/api/chat')
async Chat(@Res() res) {
const messages = await this.chatService.getMessages();
res.json(messages);
@UseGuards(JwtAuthGuard)
@Get('/rank')
async getRank(@Request() req)
{
const user = await this.userService.findOne(req.user.username);
return user.rank;
}
@UseGuards(JwtAuthGuard)
@Post('/quit')
async setOffline(@Request() req) {
const user = await this.userService.findOne(req.user.username);
user.status = 0;
await this.userService.save(user);
}
// @Get('/chat')
// async Chat(@Res() res) {
// const messages = await this.chatService.getMessages();
// res.json(messages);
// }
}

View File

@ -5,7 +5,7 @@ import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { User } from '../model/user.entity';
import { MatchLog } from '../model/user.entity';
@Injectable()
export class loginClass {
@ -56,8 +56,6 @@ export class loginClass {
if (!user) {
console.log(`no user, creating one`);
user = {
// name: null,
// description: null,
id: null,
password: null,
username: userName,
@ -66,6 +64,8 @@ export class loginClass {
loss: 0,
rank: 1200,
userId: userId,
children: null,
status: 1,
};
await this.usersService.create(user);
}

View File

@ -1,7 +1,6 @@
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity } from 'typeorm';
@Entity()
// export class Chat extends BaseEntity {
export class Chat{
@PrimaryGeneratedColumn('uuid')
id: number;
@ -15,5 +14,10 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity }
@CreateDateColumn()
createdAt: Date;
//ban user
//user list
//blocked user (in user model ?)
//op list
//a way to stock conv ?
}

View File

@ -1,5 +1,4 @@
// item.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, BaseEntity } from 'typeorm';
// import { BaseEntity } from './base.entity';
// @Column({ type: 'varchar', length: 300 , nullable: true})
@ -7,37 +6,62 @@ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity } from 'typeorm';
// @Column({ type: 'varchar', length: 300 , nullable: true})
// description: string;
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { ManyToOne, OneToMany } from 'typeorm';
@Entity({ name: 'User' })
// export class User extends BaseEntity {
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ nullable: true })
nickname: string;
@Column({ nullable: true })
username: string;
@Column({ nullable: true })
password: string;
// @Column({ nullable: true })
// email: string;
// @Column({ nullable: true })
// password: string;
@Column({ default: 0 })
win: number;
@Column({ default: 0 })
loss: number;
@Column({ default: 0 })
rank: number;
@Column({ default: 0 }) //0 = offline | 1 = connected | 2 = in game
status: number;
@Column({ default: 0 })
userId: number;
@OneToMany(() => MatchLog, child => child.parent)
children: MatchLog[];
}
@Entity()
export class MatchLog {
@PrimaryGeneratedColumn()
id: number;
@Column()
opponent: string;
@Column({ default: 0 })
myScore: number;
@Column({ default: 0 })
opScore: number;
@ManyToOne(() => User, parent => parent.children)
parent: User;
}

View File

@ -3,13 +3,14 @@ import { UsersService} from './users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { getTypeOrmConfig } from '../config/config.service';
import { User } from '../model/user.entity';
import { MatchLog, User } from '../model/user.entity';
@Module({
imports:
[
TypeOrmModule.forRoot(getTypeOrmConfig()),
TypeOrmModule.forFeature([User]),
TypeOrmModule.forFeature([MatchLog]),
// TypeOrmModule.forFeature([UserRepository]),
],
providers:[UsersService],

View File

@ -3,12 +3,14 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../model/user.entity';
import { MatchLog } from '../model/user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User) private userRepository: Repository<User>,
@InjectRepository(MatchLog) private readonly matchRepository: Repository<MatchLog>,
) {}
getHello(): string {
@ -30,6 +32,12 @@ export class UsersService {
async save(user: User): Promise<User> {
return await this.userRepository.save(user);
}
async saveChild(user: User, match: MatchLog): Promise<User> {
// user.match = savedChild;
await this.matchRepository.save(match);
return await this.userRepository.save(user);
}
}

View File

@ -58,6 +58,7 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
console.log(`Player ${player.id} joined game ${gameId}`);
});
players.forEach((player) => {
// const playersIds = game.map(socket => socket.id);
player.emit('pong:gameId', gameId);
});
}
@ -227,6 +228,22 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}
}
@SubscribeMessage('pong:name')
getName(client: Socket, payload: any): void
{
const game = this.games.get(payload.gameId);
const playersIds = game.map(socket => socket.id);
console.log(`name of client= ${payload.name}`);
if (playersIds[0] === payload.id)
{
this.clients[playersIds[1]].emit('pong:name', payload.name);
}
if (playersIds[1] === payload.id)
{
this.clients[playersIds[0]].emit('pong:name', payload.name);
}
}
}//end of Web Socket Gateway

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,92 @@
import { useEffect, useState } from "react";
import { Navigate, Route, Routes, useNavigate } from "react-router-dom";
import "../styles/App.css";
import Field from './Field';
import PlayButton from './PlayButton';
import SuccessToken from '../script/tokenSuccess'
import Home from './Home';
import api from '../script/axiosApi';
// import Login42 from './Login42';
// const navigate = useNavigate();
// const [isLoggedIn, setisLoggedIn] = useState(false);
// useEffect(() => {
// if (!localStorage.getItem('token'))
// {
// navigate("/");
// }
// else
// {
// setisLoggedIn(true);
// }
// },);
function App() {
useEffect(() => {
const handleUnload = async (event) => {
await api.post('/quit');
// Custom logic when the user is quitting the app
// You can perform any necessary cleanup or trigger actions here
// This function will be called when the user leaves the app
};
// Add the event listener when the component mounts
window.addEventListener('beforeunload', handleUnload);
// Remove the event listener when the component unmounts
return () => {
window.removeEventListener('beforeunload', handleUnload);
};
}, []);
return (
<>
<Routes>
<Route exact path="/" element={<Home/>}/>
<Route exact path="/pong" element={<PlayButton />}/>
<Route exact path="/pong/play" element={<Field />}/>
<Route exact path="/token" element={<SuccessToken />}/>
<Route path='*' element={<Navigate to='/' />} />
</Routes>
</>
);
}
export default App;
// {/* <Route path="*"><Navigate to="/" /></Route>
// */}
// {/* Gestion des pages inexistantes */}
// {/* ------- ROUTE FOR CHAT APP HERE --------- */}
// {/* <Route exact path="/chat" element={<NOM DU COMPONENT == index dans le tuto/>}/> */}
// {/* <Routes>
// {/* {redirectToUrl} */}
// <Route exact path="/" element={<Home/>}/>
// <Route exact path="/pong" element={<PlayButton />}/>
// <Route exact path="/pong/play" element={<Field />}/>
// <Route exact path="/token" element={<SuccessToken />}/>
// <Route path='*' element={<Navigate to='/' />} />
// {/* <Route path="*"><Navigate to="/" /></Route>
// */}
// {/* Gestion des pages inexistantes */}
// {/* ------- ROUTE FOR CHAT APP HERE --------- */}
// {/* <Route exact path="/chat" element={<NOM DU COMPONENT == index dans le tuto/>}/> */}
// </Routes> */}

View File

@ -0,0 +1,49 @@
import '../styles/old.css';
import '../styles/field.css';
import { useLocation } from 'react-router-dom';
import api from '../script/axiosApi';
function Home()
{
const login2 = () => {
console.log('Hello from myFunction');
api.get('/profile').then((response) => {
const data = response;
const myJSON = JSON.stringify(response.data);
console.log(`data response= ${myJSON}`)
});
}
const location = useLocation();
const handleButtonClick = () => {
const token = localStorage.getItem('token')
console.log(`token type= ${typeof token}`);
if (token !== null)
{
console.log(`already token= ${localStorage.getItem('token')}`)
return ;
}
// else
let path = "https://api.intra.42.fr/oauth/authorize?client_id=u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41&redirect_uri=http%3A%2F%2Flocalhost%3A80%2Fapi%2Fauth%2Flogin&response_type=code";
window.location.replace(path);
};
return (
<div className="notClicked">
<button onClick={handleButtonClick} className="playButton" >LOGIN</button>
<div className ="loginForm">
<button className="submit" onClick={login2}>test button</button>
</div>
<div className ="loginForm">
<button className="submit" onClick={() => api.post('/win')}>add win</button>
</div>
<div className ="loginForm">
<button className="submit" onClick={() => api.post('/loss')}>add loss</button>
</div>
</div>
);
}
export default Home;

View File

@ -1,6 +1,8 @@
// import io from 'socket.io-client';
import { useEffect } from 'react';
import api from '../script/axiosApi';
// import { useEffect } from 'react';
import io from 'socket.io-client';
// const socket = io('http://192.168.1.14:4000');
// const socket = io('http://86.209.110.20:4000');
@ -22,6 +24,8 @@ export function drawCanvas() {
//socket
let myId = 0;
let gameId = 0;
let opName;
let opRank;
//general canvas
const scale = window.devicePixelRatio;
@ -58,6 +62,7 @@ export function drawCanvas() {
//score
let myScore = 0;
let hisScore = 0;
const maxScore = 5;
let lastUpdateTime = performance.now();
@ -79,8 +84,64 @@ export function drawCanvas() {
socket.emit('pong:matchmaking', info);
}
socket.on('pong:gameId', (data) => {
// socket.on('pong:gameId', (data) => {
// console.log("gameId received")
// gameId = data;
// // api.get('/profile');
// let myName;
// api.get('/profile').then((data) => {
// // Faire quelque chose avec les données
// console.log(data);
// myName = data.data.username;
// console.log(`myname= ${myName}`);
// }).catch((error) => {
// console.log(error);
// // exit() ;
// return;
// });
// const info = {
// id: myId,
// name: myName,
// gameId: gameId,
// };
// console.log("emit to name")
// socket.emit('pong:name', info);
// });
socket.on('pong:gameId', async (data) => {
console.log("gameId received");
gameId = data;
try {
let response = await api.get('/profile');
const myName = response.data.username;
response = await api.get('/rank');
opRank = response.data
console.log(`rank= ${opRank}`);
console.log(`myname= ${myName}`);
const info = {
id: myId,
name: myName,
gameId: gameId,
rank: opRank,
};
console.log("emit to name");
socket.emit('pong:name', info);
} catch (error) {
console.log(error);
// Handle error here
return;
}
});
socket.on('pong:name', (data) => {
opName = data;
console.log(`opponent Name= ${opName}`)
});
socket.on('connect', () => {
@ -240,23 +301,43 @@ function draw(timestamp)
{
if (gameId === 0 )
{
requestAnimationFrame(draw)
return;
requestAnimationFrame(draw);
return ;
}
if (myScore === maxScore || hisScore === maxScore)
{
const data = {
myScore: myScore,
opScore: hisScore,
opName: opName,
opRank: opRank,
};
if (myScore === maxScore)
{
api.post('/win', data);
console.log("send win");
}
else
{
api.post('/loss', data);
console.log("send loose");
}
window.location.replace("http://localhost/pong");
return ;
}
const deltaTime = timestamp - lastUpdateTime;
lastUpdateTime = timestamp;
const deltaTime = timestamp - lastUpdateTime;
lastUpdateTime = timestamp;
ballX += vX * deltaTime * canvas.width;
ballY += vY * deltaTime * canvas.width;
ballX += vX * deltaTime * canvas.width;
ballY += vY * deltaTime * canvas.width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPaddle();
drawcenter();
drawball();
is_collision();
is_out();
requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPaddle();
drawcenter();
drawball();
is_collision();
is_out();
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

View File

@ -0,0 +1,58 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/index.css';
import App from './components/App';
import Header from './components/Header';
// import Home from './components/Home';
// import Login42 from './components/Login42';
import Head from './components/Head';
// import Field from './components/Field';
// import PlayButton from './components/PlayButton';
import reportWebVitals from './reportWebVitals';
// import SuccessToken from './script/tokenSuccess'
import { BrowserRouter, Route, Routes, Navigate} from 'react-router-dom'
// let redirectToUrl;
// if (localStorage.getItem('token') !== null) //check condition
// {
// redirectToUrl = <Navigate to='/'/>;
// }
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<>
<Head />
<Header />
<BrowserRouter>
<App></App>
</BrowserRouter>
</>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
{/* <Route exact path="/login42" element={<Login42 />}/> */}
// <Routes>
// {/* {redirectToUrl} */}
// <Route exact path="/" element={<Home/>}/>
// <Route exact path="/pong" element={<PlayButton />}/>
// <Route exact path="/pong/play" element={<Field />}/>
// <Route exact path="/token" element={<SuccessToken />}/>
// <Route path='*' element={<Navigate to='/' />} />
// {/* <Route path="*"><Navigate to="/" /></Route>
// */}
// {/* Gestion des pages inexistantes */}
// {/* ------- ROUTE FOR CHAT APP HERE --------- */}
// {/* <Route exact path="/chat" element={<NOM DU COMPONENT == index dans le tuto/>}/> */}
// </Routes>

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Some files were not shown because too many files have changed in this diff Show More