Merge remote-tracking branch 'origin/master' into eric_front_and_back
This commit is contained in:
106
README.md
106
README.md
@@ -1,5 +1,4 @@
|
|||||||
- CONFLICT srcs/requirements/svelte/api_front/public/build/bundle.js
|
CONFLICT srcs/requirements/nestjs/api_back/src/friendship/friendship.service.ts
|
||||||
- CONFLICT srcs/requirements/svelte/api_front/public/build/bundle.js.map
|
|
||||||
|
|
||||||
|
|
||||||
### Pour lancer le docker :
|
### Pour lancer le docker :
|
||||||
@@ -132,3 +131,106 @@
|
|||||||
- [docker](https://github.com/docker/docker-install)
|
- [docker](https://github.com/docker/docker-install)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## http status :
|
||||||
|
|
||||||
|
```
|
||||||
|
- '100': 'CONTINUE',
|
||||||
|
- '101': 'SWITCHING_PROTOCOLS',
|
||||||
|
- '102': 'PROCESSING',
|
||||||
|
- '103': 'EARLYHINTS',
|
||||||
|
- '200': 'OK',
|
||||||
|
- '201': 'CREATED',
|
||||||
|
- '202': 'ACCEPTED',
|
||||||
|
- '203': 'NON_AUTHORITATIVE_INFORMATION',
|
||||||
|
- '204': 'NO_CONTENT',
|
||||||
|
- '205': 'RESET_CONTENT',
|
||||||
|
- '206': 'PARTIAL_CONTENT',
|
||||||
|
- '300': 'AMBIGUOUS',
|
||||||
|
- '301': 'MOVED_PERMANENTLY',
|
||||||
|
- '302': 'FOUND',
|
||||||
|
- '303': 'SEE_OTHER',
|
||||||
|
- '304': 'NOT_MODIFIED',
|
||||||
|
- '307': 'TEMPORARY_REDIRECT',
|
||||||
|
- '308': 'PERMANENT_REDIRECT',
|
||||||
|
- '400': 'BAD_REQUEST',
|
||||||
|
- '401': 'UNAUTHORIZED',
|
||||||
|
- '402': 'PAYMENT_REQUIRED',
|
||||||
|
- '403': 'FORBIDDEN',
|
||||||
|
- '404': 'NOT_FOUND',
|
||||||
|
- '405': 'METHOD_NOT_ALLOWED',
|
||||||
|
- '406': 'NOT_ACCEPTABLE',
|
||||||
|
- '407': 'PROXY_AUTHENTICATION_REQUIRED',
|
||||||
|
- '408': 'REQUEST_TIMEOUT',
|
||||||
|
- '409': 'CONFLICT',
|
||||||
|
- '410': 'GONE',
|
||||||
|
- '411': 'LENGTH_REQUIRED',
|
||||||
|
- '412': 'PRECONDITION_FAILED',
|
||||||
|
- '413': 'PAYLOAD_TOO_LARGE',
|
||||||
|
- '414': 'URI_TOO_LONG',
|
||||||
|
- '415': 'UNSUPPORTED_MEDIA_TYPE',
|
||||||
|
- '416': 'REQUESTED_RANGE_NOT_SATISFIABLE',
|
||||||
|
- '417': 'EXPECTATION_FAILED',
|
||||||
|
- '418': 'I_AM_A_TEAPOT',
|
||||||
|
- '421': 'MISDIRECTED',
|
||||||
|
- '422': 'UNPROCESSABLE_ENTITY',
|
||||||
|
- '424': 'FAILED_DEPENDENCY',
|
||||||
|
- '428': 'PRECONDITION_REQUIRED',
|
||||||
|
- '429': 'TOO_MANY_REQUESTS',
|
||||||
|
- '500': 'INTERNAL_SERVER_ERROR',
|
||||||
|
- '501': 'NOT_IMPLEMENTED',
|
||||||
|
- '502': 'BAD_GATEWAY',
|
||||||
|
- '503': 'SERVICE_UNAVAILABLE',
|
||||||
|
- '504': 'GATEWAY_TIMEOUT',
|
||||||
|
- '505': 'HTTP_VERSION_NOT_SUPPORTED',
|
||||||
|
- CONTINUE: 100,
|
||||||
|
- SWITCHING_PROTOCOLS: 101,
|
||||||
|
- PROCESSING: 102,
|
||||||
|
- EARLYHINTS: 103,
|
||||||
|
- OK: 200,
|
||||||
|
- CREATED: 201,
|
||||||
|
- ACCEPTED: 202,
|
||||||
|
- NON_AUTHORITATIVE_INFORMATION: 203,
|
||||||
|
- NO_CONTENT: 204,
|
||||||
|
- RESET_CONTENT: 205,
|
||||||
|
- PARTIAL_CONTENT: 206,
|
||||||
|
- AMBIGUOUS: 300,
|
||||||
|
- MOVED_PERMANENTLY: 301,
|
||||||
|
- FOUND: 302,
|
||||||
|
- SEE_OTHER: 303,
|
||||||
|
- NOT_MODIFIED: 304,
|
||||||
|
- TEMPORARY_REDIRECT: 307,
|
||||||
|
- PERMANENT_REDIRECT: 308,
|
||||||
|
- BAD_REQUEST: 400,
|
||||||
|
- UNAUTHORIZED: 401,
|
||||||
|
- PAYMENT_REQUIRED: 402,
|
||||||
|
- FORBIDDEN: 403,
|
||||||
|
- NOT_FOUND: 404,
|
||||||
|
- METHOD_NOT_ALLOWED: 405,
|
||||||
|
- NOT_ACCEPTABLE: 406,
|
||||||
|
- PROXY_AUTHENTICATION_REQUIRED: 407,
|
||||||
|
- REQUEST_TIMEOUT: 408,
|
||||||
|
- CONFLICT: 409,
|
||||||
|
- GONE: 410,
|
||||||
|
- LENGTH_REQUIRED: 411,
|
||||||
|
- PRECONDITION_FAILED: 412,
|
||||||
|
- PAYLOAD_TOO_LARGE: 413,
|
||||||
|
- URI_TOO_LONG: 414,
|
||||||
|
- UNSUPPORTED_MEDIA_TYPE: 415,
|
||||||
|
- REQUESTED_RANGE_NOT_SATISFIABLE: 416,
|
||||||
|
- EXPECTATION_FAILED: 417,
|
||||||
|
- I_AM_A_TEAPOT: 418,
|
||||||
|
- MISDIRECTED: 421,
|
||||||
|
- UNPROCESSABLE_ENTITY: 422,
|
||||||
|
- FAILED_DEPENDENCY: 424,
|
||||||
|
- PRECONDITION_REQUIRED: 428,
|
||||||
|
- TOO_MANY_REQUESTS: 429,
|
||||||
|
- INTERNAL_SERVER_ERROR: 500,
|
||||||
|
- NOT_IMPLEMENTED: 501,
|
||||||
|
- BAD_GATEWAY: 502,
|
||||||
|
- SERVICE_UNAVAILABLE: 503,
|
||||||
|
- GATEWAY_TIMEOUT: 504,
|
||||||
|
- HTTP_VERSION_NOT_SUPPORTED: 505
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -229,8 +229,7 @@ export class GameSession {
|
|||||||
this._forfeit();
|
this._forfeit();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// WIP: envoyer un truc à Nest ? Genre "match draw"
|
this._matchEnd(en.PlayerSide.noSide, true);
|
||||||
this.destroy();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -250,10 +249,10 @@ export class GameSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _matchEnd(winner: en.PlayerSide, forfeit_flag: boolean = false)
|
private async _matchEnd(winner: en.PlayerSide, forfeitFlag: boolean = false)
|
||||||
{
|
{
|
||||||
this.matchEnded = true;
|
this.matchEnded = true;
|
||||||
const eventEnd = new ev.EventMatchEnd(winner, forfeit_flag);
|
const eventEnd = new ev.EventMatchEnd(winner, forfeitFlag);
|
||||||
this.playersMap.forEach( (client) => {
|
this.playersMap.forEach( (client) => {
|
||||||
client.socket.send(JSON.stringify(eventEnd));
|
client.socket.send(JSON.stringify(eventEnd));
|
||||||
});
|
});
|
||||||
@@ -261,19 +260,23 @@ export class GameSession {
|
|||||||
client.socket.send(JSON.stringify(eventEnd));
|
client.socket.send(JSON.stringify(eventEnd));
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: mettre à jour la route pour gerer les forfaits (actuellement le plus haut score gagne par defaut)
|
|
||||||
const gc = this.components;
|
const gc = this.components;
|
||||||
console.log("================================= MATCH ENDED");
|
console.log("================================= MATCH ENDED");
|
||||||
if (forfeit_flag) {
|
if (forfeitFlag) {
|
||||||
if (winner === en.PlayerSide.left)
|
if (winner === en.PlayerSide.left)
|
||||||
{
|
{
|
||||||
gc.scoreLeft = 3
|
gc.scoreLeft = 3;
|
||||||
gc.scoreRight = 0
|
gc.scoreRight = 0;
|
||||||
|
}
|
||||||
|
else if (winner === en.PlayerSide.right)
|
||||||
|
{
|
||||||
|
gc.scoreLeft = 0;
|
||||||
|
gc.scoreRight = 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gc.scoreLeft = 0
|
gc.scoreLeft = 0;
|
||||||
gc.scoreRight = 3
|
gc.scoreRight = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fetch(c.addressBackEnd + "/game/gameserver/updategame",
|
await fetch(c.addressBackEnd + "/game/gameserver/updategame",
|
||||||
|
|||||||
@@ -150,10 +150,10 @@ function publicMatchmaking(player: ClientPlayer)
|
|||||||
{
|
{
|
||||||
const minPlayersNumber = 2;
|
const minPlayersNumber = 2;
|
||||||
const maxPlayersNumber = 2;
|
const maxPlayersNumber = 2;
|
||||||
matchmakingMap.set(player.id, player);
|
|
||||||
const matchOptions = player.matchOptions;
|
const matchOptions = player.matchOptions;
|
||||||
|
|
||||||
const compatiblePlayers: ClientPlayer[] = [];
|
const compatiblePlayers: ClientPlayer[] = [];
|
||||||
|
compatiblePlayers.push(player);
|
||||||
for (const [id, client] of matchmakingMap)
|
for (const [id, client] of matchmakingMap)
|
||||||
{
|
{
|
||||||
if (client.matchOptions === matchOptions)
|
if (client.matchOptions === matchOptions)
|
||||||
@@ -165,12 +165,27 @@ function publicMatchmaking(player: ClientPlayer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Replace with this code to disable the possibility to play against self
|
||||||
|
/* for (const [id, client] of matchmakingMap)
|
||||||
|
{
|
||||||
|
if (client.matchOptions === matchOptions && client.username !== player.username)
|
||||||
|
{
|
||||||
|
compatiblePlayers.push(client);
|
||||||
|
if (compatiblePlayers.length === maxPlayersNumber) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
if (compatiblePlayers.length >= minPlayersNumber) {
|
if (compatiblePlayers.length >= minPlayersNumber) {
|
||||||
compatiblePlayers.forEach((client) => {
|
compatiblePlayers.forEach((client) => {
|
||||||
matchmakingMap.delete(client.id);
|
matchmakingMap.delete(client.id);
|
||||||
});
|
});
|
||||||
createGameSession(compatiblePlayers, matchOptions);
|
createGameSession(compatiblePlayers, matchOptions);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
matchmakingMap.set(player.id, player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -178,11 +193,11 @@ function privateMatchmaking(player: ClientPlayer)
|
|||||||
{
|
{
|
||||||
const minPlayersNumber = 2;
|
const minPlayersNumber = 2;
|
||||||
const maxPlayersNumber = 2;
|
const maxPlayersNumber = 2;
|
||||||
privateMatchmakingMap.set(player.id, player);
|
|
||||||
const matchOptions = player.matchOptions;
|
const matchOptions = player.matchOptions;
|
||||||
|
|
||||||
const token = player.token;
|
const token = player.token;
|
||||||
const compatiblePlayers: ClientPlayer[] = [];
|
const compatiblePlayers: ClientPlayer[] = [];
|
||||||
|
compatiblePlayers.push(player);
|
||||||
for (const [id, client] of privateMatchmakingMap)
|
for (const [id, client] of privateMatchmakingMap)
|
||||||
{
|
{
|
||||||
if (client.token === token)
|
if (client.token === token)
|
||||||
@@ -202,6 +217,7 @@ function privateMatchmaking(player: ClientPlayer)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
privateMatchmakingMap.set(player.id, player);
|
||||||
setTimeout(async function abortMatch() {
|
setTimeout(async function abortMatch() {
|
||||||
if (!player.gameSession)
|
if (!player.gameSession)
|
||||||
{
|
{
|
||||||
@@ -226,7 +242,6 @@ function privateMatchmaking(player: ClientPlayer)
|
|||||||
|
|
||||||
function createGameSession(playersArr: ClientPlayer[], matchOptions: en.MatchOptions)
|
function createGameSession(playersArr: ClientPlayer[], matchOptions: en.MatchOptions)
|
||||||
{
|
{
|
||||||
// const id = c.gameSessionIdPLACEHOLDER; // Force ID, TESTING SPECTATOR
|
|
||||||
const id = uuidv4();
|
const id = uuidv4();
|
||||||
const gameSession = new GameSession(id, matchOptions);
|
const gameSession = new GameSession(id, matchOptions);
|
||||||
gameSessionsMap.set(id, gameSession);
|
gameSessionsMap.set(id, gameSession);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export enum InputEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum PlayerSide {
|
export enum PlayerSide {
|
||||||
|
noSide = 0,
|
||||||
left = 1,
|
left = 1,
|
||||||
right
|
right
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
NODE_ENV=development
|
|
||||||
POSTGRES_HOST=postgresql
|
|
||||||
POSTGRES_PORT=5432
|
|
||||||
POSTGRES_USERNAME=postgres
|
|
||||||
POSTGRES_PASSWORD=9pKpKEgiamxwk5P7Ggsz
|
|
||||||
POSTGRES_DATABASE=transcendance_db
|
|
||||||
|
|
||||||
# OAUTH2 42 API
|
|
||||||
FORTYTWO_CLIENT_ID=u-s4t2ud-49dc7b539bcfe1acb48b928b2b281671c99fc5bfab1faca57a536ab7e0075500
|
|
||||||
FORTYTWO_CLIENT_SECRET=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
|
|
||||||
FORTYTWO_CALLBACK_URL=http://transcendance:8080/api/v2/auth/redirect
|
|
||||||
COOKIE_SECRET=248cdc831110eec8796d7c1edbf79835
|
|
||||||
# JWT
|
|
||||||
JWT_SECRET=442d774798979fcc14a4a2b6b7535902
|
|
||||||
# Misc
|
|
||||||
PORT=3000
|
|
||||||
#Redis
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_PASSWORD=1a5e04138b91b3d683c708e4689454c2
|
|
||||||
#2fa
|
|
||||||
TWO_FACTOR_AUTHENTICATION_APP_NAME=Transcendance
|
|
||||||
@@ -9,6 +9,7 @@ import { AuthenticationModule } from './auth/42/authentication.module';
|
|||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { GameModule } from './game/game.module';
|
import { GameModule } from './game/game.module';
|
||||||
import { ChatGateway } from './chat/chat.gateway';
|
import { ChatGateway } from './chat/chat.gateway';
|
||||||
|
import { ChatModule } from './chat/chat.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -30,12 +31,10 @@ import { ChatGateway } from './chat/chat.gateway';
|
|||||||
//avec une classe pour le module
|
//avec une classe pour le module
|
||||||
synchronize: true,
|
synchronize: true,
|
||||||
}),
|
}),
|
||||||
|
ChatModule,
|
||||||
// GameModule,
|
// GameModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [
|
providers: [AppService],
|
||||||
AppService,
|
|
||||||
ChatGateway,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
105
srcs/requirements/nestjs/api_back/src/chat/chat.controller.ts
Normal file
105
srcs/requirements/nestjs/api_back/src/chat/chat.controller.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import { Controller, UseGuards, HttpException, HttpStatus, Get, Post, Body, Req, Res } from '@nestjs/common';
|
||||||
|
import { AuthenticateGuard, TwoFactorGuard } from 'src/auth/42/guards/42guards';
|
||||||
|
import { ConnectedSocket } from '@nestjs/websockets';
|
||||||
|
import { ChatService } from './chat.service';
|
||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
import { PartialUsersDto } from 'src/users/dto/partial-users.dto';
|
||||||
|
import { createRoomDto } from './dto/createRoom.dto';
|
||||||
|
import { joinRoomDto } from './dto/joinRoom.dto';
|
||||||
|
import { setCurrentRoomDto } from './dto/setCurrentRoom.dto';
|
||||||
|
|
||||||
|
@Controller('chat')
|
||||||
|
export class ChatController {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private chatService: ChatService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Get('myrooms')
|
||||||
|
async getMyRooms(@Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in getMyRooms controller");
|
||||||
|
const rooms = await this.chatService.getMyRooms(req.user);
|
||||||
|
console.log("- out getMyRooms controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ rooms: rooms });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Get('allrooms')
|
||||||
|
async getAllRooms(@Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in getAllRooms controller");
|
||||||
|
const rooms = await this.chatService.getAllNotMyRooms(req.user);
|
||||||
|
console.log("- out getAllRooms controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ rooms: rooms });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Get('current')
|
||||||
|
async setCurrentRoom(@Body() setCurrentRoomDto: setCurrentRoomDto, @Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in setCurrentRoom controller");
|
||||||
|
const response = await this.chatService.setCurrentRoom(req.user, setCurrentRoomDto.name);
|
||||||
|
console.log("- out setCurrentRoom controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ message: response });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Post('create')
|
||||||
|
async createRoom(@Body() createRoomDto: createRoomDto, @Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in createRoom controller");
|
||||||
|
const response = await this.chatService.addUserToNewRoom(req.user, createRoomDto);
|
||||||
|
console.log("- out createRoom controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ room_name: createRoomDto.room_name, message: response });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Post('join')
|
||||||
|
async joinRoom(@Body() joinRoomDto: joinRoomDto, @Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in joinRoom controller");
|
||||||
|
const response = await this.chatService.addUserToRoom(req.user, joinRoomDto);
|
||||||
|
console.log("- out joinRoom controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ room_name: joinRoomDto.room_name, message: response });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Post('change')
|
||||||
|
async changeRoom(@Body() joinRoomDto: joinRoomDto, @Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in changeRoom controller");
|
||||||
|
const response = await this.chatService.setCurrentRoom(req.user, joinRoomDto.room_name);
|
||||||
|
console.log("- out changeRoom controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ room_name: joinRoomDto.room_name, message: response });
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Post('leave')
|
||||||
|
async leaveRoom(@Body() body)
|
||||||
|
{
|
||||||
|
console.log("- in leaveRoom controller");
|
||||||
|
console.log("- out leaveRoom controller");
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AuthenticateGuard)
|
||||||
|
@UseGuards(TwoFactorGuard)
|
||||||
|
@Get('messages')
|
||||||
|
async getMessages(@Req() req, @Res() res): Promise<object>
|
||||||
|
{
|
||||||
|
console.log("- in getMessages controller");
|
||||||
|
const messages = await this.chatService.getMessagesFromCurrentRoom(req.user);
|
||||||
|
console.log("- out getMessages controller");
|
||||||
|
return res.status(HttpStatus.OK).json({ messages: messages });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
import {
|
import { WebSocketGateway, SubscribeMessage, WebSocketServer, MessageBody, ConnectedSocket, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
|
||||||
WebSocketGateway,
|
|
||||||
SubscribeMessage,
|
|
||||||
WebSocketServer,
|
|
||||||
MessageBody,
|
|
||||||
OnGatewayConnection,
|
|
||||||
OnGatewayDisconnect,
|
|
||||||
} from '@nestjs/websockets';
|
|
||||||
import { UsersService } from 'src/users/users.service';
|
import { UsersService } from 'src/users/users.service';
|
||||||
import { PaginationQueryDto } from 'src/common/dto/pagination-query.dto';
|
import { PaginationQueryDto } from 'src/common/dto/pagination-query.dto';
|
||||||
|
import { ChatService } from './chat.service';
|
||||||
|
|
||||||
@WebSocketGateway(5000, {
|
@WebSocketGateway(5000, {
|
||||||
path: '/chat',
|
path: '/chat',
|
||||||
@@ -19,26 +13,43 @@ export class ChatGateway
|
|||||||
constructor
|
constructor
|
||||||
(
|
(
|
||||||
private usersService: UsersService,
|
private usersService: UsersService,
|
||||||
|
private chatService: ChatService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@WebSocketServer()
|
@WebSocketServer()
|
||||||
server;
|
server;
|
||||||
|
|
||||||
|
|
||||||
// how to guard the handleConnection ?
|
// how to guard the handleConnection ?
|
||||||
// https://github.com/nestjs/nest/issues/882
|
// https://github.com/nestjs/nest/issues/882
|
||||||
async handleConnection(client) {
|
async handleConnection(client) {
|
||||||
// const paginationQuery = new PaginationQueryDto();
|
console.log('- Client connected :', client.id, client.handshake.query.username);
|
||||||
// const users = await this.usersService.findAll(paginationQuery);
|
client.username = client.handshake.query.username;
|
||||||
|
}
|
||||||
|
async handleDisconnect(client) {
|
||||||
|
console.log('- Client disconnected :', client.id, client.username);
|
||||||
|
}
|
||||||
|
|
||||||
// const users = await this.usersService.findAll(client);
|
@SubscribeMessage('join')
|
||||||
// const users = await this.usersService.findAll(client);
|
async joinRoom(@ConnectedSocket() socket, @MessageBody() room_name: string): Promise<void>
|
||||||
console.log('---- Client connected :', client.id);
|
{
|
||||||
// console.log('users :', users);
|
console.log('- in joinRoom gateway');
|
||||||
|
socket.leave(socket.room);
|
||||||
|
socket.join(room_name);
|
||||||
|
socket.room = room_name;
|
||||||
|
|
||||||
|
console.log('- out joinRoom gateway');
|
||||||
}
|
}
|
||||||
handleDisconnect(client) {
|
|
||||||
console.log('---- client disconnected :', client.id);
|
@SubscribeMessage('message')
|
||||||
|
async handleMessage(@ConnectedSocket() socket, @MessageBody() message: string): Promise<void>
|
||||||
|
{
|
||||||
|
console.log('- in handleMessage gateway');
|
||||||
|
//let room_name = await this.chatService.getCurrentRoom(socket.username);
|
||||||
|
socket.to(socket.room).emit('message', socket.username, message);
|
||||||
|
this.chatService.addMessageToCurrentRoom(socket.username, message);
|
||||||
|
|
||||||
|
console.log('- out handleMessage gateway');
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
srcs/requirements/nestjs/api_back/src/chat/chat.module.ts
Normal file
28
srcs/requirements/nestjs/api_back/src/chat/chat.module.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ChatController } from './chat.controller';
|
||||||
|
import { ChatService } from './chat.service';
|
||||||
|
import { ChatGateway } from './chat.gateway';
|
||||||
|
import { UsersModule } from 'src/users/users.module';
|
||||||
|
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { Chatroom } from './entities/chatroom.entity';
|
||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([Chatroom, User]),
|
||||||
|
UsersModule,
|
||||||
|
],
|
||||||
|
controllers: [
|
||||||
|
ChatController,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
ChatService,
|
||||||
|
ChatGateway,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export class ChatModule {}
|
||||||
|
|
||||||
219
srcs/requirements/nestjs/api_back/src/chat/chat.service.ts
Normal file
219
srcs/requirements/nestjs/api_back/src/chat/chat.service.ts
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
import { HttpException, HttpStatus, Injectable, Res } from '@nestjs/common';
|
||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
import { UsersService } from 'src/users/users.service';
|
||||||
|
import { Chatroom } from './entities/chatroom.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { createRoomDto } from './dto/createRoom.dto';
|
||||||
|
import { joinRoomDto } from './dto/joinRoom.dto';
|
||||||
|
import { messagesDto } from './dto/messages.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ChatService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private usersService: UsersService,
|
||||||
|
@InjectRepository(User)
|
||||||
|
private readonly userRepository: Repository<User>,
|
||||||
|
@InjectRepository(Chatroom)
|
||||||
|
private readonly chatroomRepository: Repository<Chatroom>,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
|
||||||
|
// temp for test
|
||||||
|
sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* GETTERS ************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getMyRooms(user: User)
|
||||||
|
{
|
||||||
|
console.log("-- in getMyRooms service");
|
||||||
|
const rooms = await this.chatroomRepository
|
||||||
|
.createQueryBuilder('chatroom')
|
||||||
|
.where('chatroom.users LIKE :user_name', { user_name: `%${user.username}%` })
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
console.log("-- out getMyRooms service");
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllRooms()
|
||||||
|
{
|
||||||
|
console.log("-- in getAllRooms service");
|
||||||
|
const rooms = await this.chatroomRepository
|
||||||
|
.createQueryBuilder('chatroom')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
console.log("-- out getAllRooms service");
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllNotMyRooms(user: User)
|
||||||
|
{
|
||||||
|
console.log("-- in getAllNotMyRooms service");
|
||||||
|
const user_db = await this.getUserByName(user.username);
|
||||||
|
//const user_db = await this.usersService.findOne(user.username);
|
||||||
|
const rooms = await this.chatroomRepository
|
||||||
|
.createQueryBuilder('chatroom')
|
||||||
|
.where('chatroom.type != :type', { type: 'private' })
|
||||||
|
.andWhere('chatroom.users NOT LIKE :user_name', { user_name: `%${user.username}%` })
|
||||||
|
.getMany();
|
||||||
|
//const users = await this.getAllUsers();
|
||||||
|
//let allRooms = [...rooms, ...users];
|
||||||
|
|
||||||
|
console.log("-- out getAllNotMyRooms service");
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMessagesFromCurrentRoom(user: User)
|
||||||
|
{
|
||||||
|
console.log("-- in getMessagesFromCurrentRoom service");
|
||||||
|
const user_db = await this.getUserByName(user.username);
|
||||||
|
//const user_db = await this.usersService.findOne(user.username);
|
||||||
|
const currentRoom = await this.getRoomByName(user_db.currentRoom);
|
||||||
|
|
||||||
|
console.log("-- out getMessagesFromCurrentRoom service");
|
||||||
|
return currentRoom.messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentRoom(username: string)
|
||||||
|
{
|
||||||
|
console.log("-- in getCurrentRoom service");
|
||||||
|
const user_db = await this.getUserByName(username);
|
||||||
|
//const user_db = await this.usersService.findOne(username);
|
||||||
|
|
||||||
|
console.log("-- out getCurrentRoom service");
|
||||||
|
return user_db.currentRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRoomByName(name: string)
|
||||||
|
{
|
||||||
|
console.log("-- in getRoomByName service");
|
||||||
|
const room = await this.chatroomRepository
|
||||||
|
.createQueryBuilder('chatroom')
|
||||||
|
.where('chatroom.name = :name', { name: name })
|
||||||
|
.getOne();
|
||||||
|
|
||||||
|
console.log("-- out getRoomByName service");
|
||||||
|
return room;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRoomById(id: number)
|
||||||
|
{
|
||||||
|
console.log("-- in getRoomById service");
|
||||||
|
const room = await this.chatroomRepository
|
||||||
|
.createQueryBuilder('chatroom')
|
||||||
|
.where('chatroom.id = :id', { id: id })
|
||||||
|
.getOne();
|
||||||
|
|
||||||
|
console.log("-- out getRoomById service");
|
||||||
|
return room;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SETTERS ************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
async setCurrentRoom(user: User, name: string)
|
||||||
|
{
|
||||||
|
console.log("-- in setCurrentRoom service");
|
||||||
|
const user_db = await this.getUserByName(user.username);
|
||||||
|
//const user_db = await this.usersService.findOne(user.username);
|
||||||
|
user_db.currentRoom = name;
|
||||||
|
this.userRepository.save(user_db);
|
||||||
|
|
||||||
|
console.log("-- out setCurrentRoom service");
|
||||||
|
return `room "${name}" is now current room`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ADDERS *************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
async addUserToNewRoom(user: User, createRoomDto: createRoomDto)
|
||||||
|
{
|
||||||
|
console.log("-- in addUserToRoom service");
|
||||||
|
const room = await this.getRoomByName(createRoomDto.room_name);
|
||||||
|
if (room)
|
||||||
|
throw new HttpException(`This room already exist`, HttpStatus.CONFLICT);
|
||||||
|
|
||||||
|
// create chatroom
|
||||||
|
const newChatroom = new Chatroom();
|
||||||
|
newChatroom.name = createRoomDto.room_name;
|
||||||
|
newChatroom.type = createRoomDto.room_type;
|
||||||
|
newChatroom.owner = user.username;
|
||||||
|
newChatroom.users = [user.username];
|
||||||
|
newChatroom.messages = [{ name: "SERVER", message: `creation of room ${createRoomDto.room_name}` }];
|
||||||
|
this.chatroomRepository.save(newChatroom);
|
||||||
|
|
||||||
|
console.log("-- out addUserToRoom service");
|
||||||
|
return "successfull room creation";
|
||||||
|
}
|
||||||
|
|
||||||
|
async addUserToRoom(user: User, joinRoomDto: joinRoomDto)
|
||||||
|
{
|
||||||
|
console.log("-- in addUserToRoom service");
|
||||||
|
const room = await this.getRoomByName(joinRoomDto.room_name);
|
||||||
|
if (room.users.includes(user.username))
|
||||||
|
throw new HttpException(`your have already join this room`, HttpStatus.CONFLICT);
|
||||||
|
|
||||||
|
// update room with new user
|
||||||
|
room.users.push(user.username);
|
||||||
|
this.chatroomRepository.save(room);
|
||||||
|
|
||||||
|
const rooms = await this.getMyRooms(user);
|
||||||
|
const allRooms = await this.getAllRooms();
|
||||||
|
|
||||||
|
console.log("-- out addUserToRoom service");
|
||||||
|
return "successfull joining room";
|
||||||
|
}
|
||||||
|
|
||||||
|
async addMessageToCurrentRoom(username: string, message: string)
|
||||||
|
{
|
||||||
|
console.log("-- in addMessageToCurrentRoom service");
|
||||||
|
const user_db = await this.getUserByName(username);
|
||||||
|
//const user_db = await this.usersService.findOne(username);
|
||||||
|
const currentRoom = await this.getRoomByName(user_db.currentRoom);
|
||||||
|
let chat_message = {
|
||||||
|
name: username,
|
||||||
|
message: message,
|
||||||
|
};
|
||||||
|
currentRoom.messages.push(chat_message);
|
||||||
|
this.chatroomRepository.save(currentRoom);
|
||||||
|
|
||||||
|
console.log("-- out addMessageToCurrentRoom service");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* REMOVERS ***********************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeUserFromRoom(user: User, room_name: string)
|
||||||
|
{
|
||||||
|
console.log("-- in removeUserFromRoom service");
|
||||||
|
// get room
|
||||||
|
// remove user
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SEARCH IN USER *****************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getUserByName(name: string)
|
||||||
|
{
|
||||||
|
console.log("-- in getUserByName service");
|
||||||
|
const user = await this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.where('user.username = :name', { name: name })
|
||||||
|
.getOne();
|
||||||
|
|
||||||
|
console.log("-- out getUserByName service");
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { IsBoolean, IsEmpty, IsInt, IsNotEmpty, IsNumber, IsString, IsOptional } from "class-validator";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
|
||||||
|
export class createRoomDto
|
||||||
|
{
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
room_name: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
room_type: 'public' | 'private' | 'direct';
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
room_password: string;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { IsBoolean, IsEmpty, IsInt, IsNotEmpty, IsNumber, IsString, IsOptional } from "class-validator";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
|
||||||
|
export class joinRoomDto
|
||||||
|
{
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
room_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { IsBoolean, IsEmpty, IsInt, IsNotEmpty, IsNumber, IsString, IsOptional, IsArray } from "class-validator";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
|
||||||
|
export class messagesDto
|
||||||
|
{
|
||||||
|
@IsArray()
|
||||||
|
messages: { name: string; message: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { IsBoolean, IsEmpty, IsInt, IsNotEmpty, IsNumber, IsString, IsOptional } from "class-validator";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
|
||||||
|
export class setCurrentRoomDto
|
||||||
|
{
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
ManyToOne,
|
||||||
|
ManyToMany,
|
||||||
|
JoinTable,
|
||||||
|
PrimaryGeneratedColumn
|
||||||
|
} from "typeorm";
|
||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
|
||||||
|
@Entity('chatroom')
|
||||||
|
export class Chatroom {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
// @ManyToOne(type => User, user => user.ownedRooms)
|
||||||
|
// owner: User;
|
||||||
|
//
|
||||||
|
// @ManyToMany(type => User)
|
||||||
|
// @JoinTable()
|
||||||
|
// users: User[];
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
owner: string; // name
|
||||||
|
|
||||||
|
@Column("simple-array")
|
||||||
|
users: string[]; // names
|
||||||
|
|
||||||
|
@Column("json")
|
||||||
|
messages: { name: string, message: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -254,7 +254,6 @@ export class FriendshipService {
|
|||||||
|
|
||||||
// const friendship = await this.friendshipRepository.findOneBy({ sender: creator, receiver: receiver });
|
// const friendship = await this.friendshipRepository.findOneBy({ sender: creator, receiver: receiver });
|
||||||
|
|
||||||
|
|
||||||
const friendship = await this.friendshipRepository
|
const friendship = await this.friendshipRepository
|
||||||
.createQueryBuilder('friendship')
|
.createQueryBuilder('friendship')
|
||||||
.leftJoinAndSelect('friendship.sender', 'sender')
|
.leftJoinAndSelect('friendship.sender', 'sender')
|
||||||
|
|||||||
@@ -87,10 +87,12 @@ export class GameService {
|
|||||||
if (user.status === STATUS.IN_POOL || user.status === STATUS.IN_GAME)
|
if (user.status === STATUS.IN_POOL || user.status === STATUS.IN_GAME)
|
||||||
{
|
{
|
||||||
await this.deleteToken(user);
|
await this.deleteToken(user);
|
||||||
|
if (user.status === STATUS.IN_POOL) {
|
||||||
user.status = STATUS.CONNECTED;
|
user.status = STATUS.CONNECTED;
|
||||||
|
}
|
||||||
this.userRepository.save(user);
|
this.userRepository.save(user);
|
||||||
}
|
}
|
||||||
if (grantTicketDto.isGameIsWithInvitation === true)
|
if (grantTicketDto.isGameIsWithInvitation === true && user.status !== STATUS.IN_GAME)
|
||||||
{
|
{
|
||||||
const secondUser : Partial<User> = await this.userService.findOne(grantTicketDto.playerTwoUsername)
|
const secondUser : Partial<User> = await this.userService.findOne(grantTicketDto.playerTwoUsername)
|
||||||
if (!secondUser || secondUser.username === user.username)
|
if (!secondUser || secondUser.username === user.username)
|
||||||
@@ -105,7 +107,7 @@ export class GameService {
|
|||||||
this.userService.updateStatus(user.id, "In Pool")
|
this.userService.updateStatus(user.id, "In Pool")
|
||||||
return res.status(HttpStatus.OK).json({ token : encryptedTextToReturn });
|
return res.status(HttpStatus.OK).json({ token : encryptedTextToReturn });
|
||||||
}
|
}
|
||||||
else if (grantTicketDto.isGameIsWithInvitation === false) {
|
else if (grantTicketDto.isGameIsWithInvitation === false && user.status !== STATUS.IN_GAME) {
|
||||||
const encryptedTextToReturn = await this.encryptToken(user.username + '_'
|
const encryptedTextToReturn = await this.encryptToken(user.username + '_'
|
||||||
+ grantTicketDto.gameOptions + '_' + grantTicketDto.isGameIsWithInvitation + '_' + new Date())
|
+ grantTicketDto.gameOptions + '_' + grantTicketDto.isGameIsWithInvitation + '_' + new Date())
|
||||||
const tok = this.tokenGameRepository.create(grantTicketDto);
|
const tok = this.tokenGameRepository.create(grantTicketDto);
|
||||||
@@ -280,6 +282,7 @@ export class GameService {
|
|||||||
{
|
{
|
||||||
this.userService.incrementDraws(playerOne.id)
|
this.userService.incrementDraws(playerOne.id)
|
||||||
this.userService.incrementDraws(playerTwo.id)
|
this.userService.incrementDraws(playerTwo.id)
|
||||||
|
console.log("DRAW NEST");
|
||||||
}
|
}
|
||||||
else if (game.playerOneUsernameResult < game.playerTwoUsernameResult)
|
else if (game.playerOneUsernameResult < game.playerTwoUsernameResult)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,4 +52,9 @@ export class User {
|
|||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@OneToOne(() => UserStats, { cascade: true })
|
@OneToOne(() => UserStats, { cascade: true })
|
||||||
stats: UserStats;
|
stats: UserStats;
|
||||||
|
|
||||||
|
// ROOMS :
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
currentRoom: string; // chatroom name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class UsersService {
|
|||||||
isEnabledTwoFactorAuth: user.isEnabledTwoFactorAuth,
|
isEnabledTwoFactorAuth: user.isEnabledTwoFactorAuth,
|
||||||
status: user.status,
|
status: user.status,
|
||||||
stats: user.stats,
|
stats: user.stats,
|
||||||
|
currentRoom: user.currentRoom,
|
||||||
};
|
};
|
||||||
console.log(`Returned Partial User.` + partialUser.username + user.username);
|
console.log(`Returned Partial User.` + partialUser.username + user.username);
|
||||||
return partialUser;
|
return partialUser;
|
||||||
@@ -193,7 +194,7 @@ export class UsersService {
|
|||||||
.getOne();
|
.getOne();
|
||||||
if (!user.stats || !user)
|
if (!user.stats || !user)
|
||||||
throw new HttpException(`The user's stats could not be found.`,HttpStatus.NOT_FOUND);
|
throw new HttpException(`The user's stats could not be found.`,HttpStatus.NOT_FOUND);
|
||||||
user.stats.winGame++;
|
user.stats.drawGame++;
|
||||||
user.stats.totalGame++;
|
user.stats.totalGame++;
|
||||||
this.userRepository.save(user);
|
this.userRepository.save(user);
|
||||||
}
|
}
|
||||||
|
|||||||
55
srcs/requirements/nginx/conf/.nfs000000000ef7127e000000f0
Normal file
55
srcs/requirements/nginx/conf/.nfs000000000ef7127e000000f0
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
listen [::]:8080;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location /api/v2 {
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_pass http://backend_dev:3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /chat {
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
proxy_pass http://backend_dev:5000/chat;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2/game/gameserver {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /pong {
|
||||||
|
proxy_pass http://game_server:8042/pong;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_pass http://frontend_dev:8080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 35729 default_server;
|
||||||
|
listen [::]:35729 default_server;
|
||||||
|
server_name localhost;
|
||||||
|
location / {
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_pass http://frontend_dev:35729;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
srcs/requirements/svelte/api_front/.env
Normal file
2
srcs/requirements/svelte/api_front/.env
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
WEBSITE_HOST=localhost
|
||||||
|
WEBSITE_PORT=8080
|
||||||
24328
srcs/requirements/svelte/api_front/public/build/bundle.js
Normal file
24328
srcs/requirements/svelte/api_front/public/build/bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -13,26 +13,22 @@
|
|||||||
let allUsers;
|
let allUsers;
|
||||||
|
|
||||||
//Game's stuff
|
//Game's stuff
|
||||||
let optionsAreNotSet = true;
|
|
||||||
const options = new pong.InitOptions();
|
const options = new pong.InitOptions();
|
||||||
|
|
||||||
//Game's stuff client side only
|
|
||||||
const gameAreaId = "game_area";
|
const gameAreaId = "game_area";
|
||||||
|
|
||||||
//html boolean for pages
|
//boolean for html page
|
||||||
let showWaitPage = false;
|
|
||||||
let showInvitations = false;
|
|
||||||
let showGameOption = true;
|
|
||||||
let showError = false;
|
|
||||||
let hiddenGame = true;
|
let hiddenGame = true;
|
||||||
let showMatchEnded = false;
|
let optionsAreNotSet = true;
|
||||||
|
let showGameOptions = true;
|
||||||
|
let showInvitations = false;
|
||||||
|
let showError = false;
|
||||||
|
let errorMessage = "";
|
||||||
|
let showWaitPage = false;
|
||||||
|
|
||||||
let isThereAnyInvitation = false;
|
|
||||||
let invitations = [];
|
let invitations = [];
|
||||||
|
|
||||||
let waitingMessage = "Please wait..."
|
let watchGameStateInterval;
|
||||||
let errorMessageWhenAttemptingToGetATicket = "";
|
const watchGameStateIntervalRate = 142;
|
||||||
let idOfIntevalCheckTerminationOfTheMatch;
|
|
||||||
|
|
||||||
onMount( async() => {
|
onMount( async() => {
|
||||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||||
@@ -43,17 +39,28 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
onDestroy( async() => {
|
onDestroy( async() => {
|
||||||
clearInterval(idOfIntevalCheckTerminationOfTheMatch);
|
clearInterval(watchGameStateInterval);
|
||||||
pong.destroy();
|
pong.destroy();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function resetPage() {
|
||||||
|
hiddenGame = true;
|
||||||
|
optionsAreNotSet = true;
|
||||||
|
showGameOptions = true;
|
||||||
|
showInvitations = false;
|
||||||
|
showError = false;
|
||||||
|
showWaitPage = false;
|
||||||
|
options.reset(user.username);
|
||||||
|
pong.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
const initGame = async() =>
|
const initGame = async() =>
|
||||||
{
|
{
|
||||||
optionsAreNotSet = false;
|
optionsAreNotSet = false;
|
||||||
showWaitPage = true;
|
showWaitPage = true;
|
||||||
const matchOptions = pong.computeMatchOptions(options);
|
const matchOptions = pong.computeMatchOptions(options);
|
||||||
|
try {
|
||||||
const responseWhenGrantToken = fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/ticket`, {
|
const response = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/ticket`, {
|
||||||
method : "POST",
|
method : "POST",
|
||||||
headers : {'Content-Type': 'application/json'},
|
headers : {'Content-Type': 'application/json'},
|
||||||
body : JSON.stringify({
|
body : JSON.stringify({
|
||||||
@@ -62,89 +69,82 @@
|
|||||||
gameOptions : matchOptions,
|
gameOptions : matchOptions,
|
||||||
isGameIsWithInvitation : options.isSomeoneIsInvited
|
isGameIsWithInvitation : options.isSomeoneIsInvited
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
const responseFromServer = await responseWhenGrantToken;
|
console.log("status : " + response.status);
|
||||||
const responseInjson = await responseFromServer.json();
|
const responseBody = await response.json();
|
||||||
const token : string = responseInjson.token;
|
const token : string = responseBody.token;
|
||||||
showWaitPage = false;
|
showWaitPage = false;
|
||||||
console.log("status : " + responseFromServer.status)
|
if (response.ok && token)
|
||||||
if (responseFromServer.status != 200)
|
|
||||||
{
|
{
|
||||||
console.log(responseInjson)
|
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
|
||||||
console.log("On refuse le ticket");
|
pong.init(matchOptions, options, gameAreaId, token);
|
||||||
errorMessageWhenAttemptingToGetATicket = responseInjson.message;
|
|
||||||
showError = true;
|
|
||||||
options.reset();
|
|
||||||
options.playerOneUsername = user.username;
|
|
||||||
setTimeout(() => {
|
|
||||||
optionsAreNotSet = true
|
|
||||||
showError = false;
|
|
||||||
// showWaitPage = false // ???
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
else if (token)
|
|
||||||
{
|
|
||||||
idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000);
|
|
||||||
// options.isInvitedPerson = false // ???
|
|
||||||
pong.init(options, gameAreaId, token);
|
|
||||||
hiddenGame = false;
|
hiddenGame = false;
|
||||||
}
|
}
|
||||||
// TODO: Un "else" peut-être ? Si pas de token on fait un truc ?
|
else
|
||||||
// Si on ne rentre pas dans le else if, du coup il ne se passe rien.
|
{
|
||||||
|
console.log(responseBody);
|
||||||
|
console.log("On refuse le ticket");
|
||||||
|
errorMessage = responseBody.message;
|
||||||
|
showError = true;
|
||||||
|
options.reset(user.username);
|
||||||
|
setTimeout(() => {
|
||||||
|
optionsAreNotSet = true;
|
||||||
|
showError = false;
|
||||||
|
errorMessage = "";
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const initGameForInvitedPlayer = async(invitation : any) =>
|
const initGameForInvitedPlayer = async(invitation : any) =>
|
||||||
{
|
{
|
||||||
optionsAreNotSet = false
|
optionsAreNotSet = false;
|
||||||
showWaitPage = true
|
showWaitPage = true;
|
||||||
console.log("invitation : ")
|
console.log("invitation : ");
|
||||||
console.log(invitation)
|
console.log(invitation);
|
||||||
if (invitation.token)
|
if (invitation.token)
|
||||||
{
|
{
|
||||||
idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000);
|
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
|
||||||
options.playerOneUsername = invitation.playerOneUsername;
|
options.playerOneUsername = invitation.playerOneUsername;
|
||||||
options.playerTwoUsername = invitation.playerTwoUsername;
|
options.playerTwoUsername = invitation.playerTwoUsername;
|
||||||
options.isSomeoneIsInvited = true;
|
options.isSomeoneIsInvited = true;
|
||||||
options.isInvitedPerson = true
|
options.isInvitedPerson = true;
|
||||||
pong.init(options, gameAreaId, invitation.token);
|
pong.init(invitation.gameOptions, options, gameAreaId, invitation.token);
|
||||||
showWaitPage = false
|
showWaitPage = false;
|
||||||
hiddenGame = false;
|
hiddenGame = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchTermitation = () => {
|
const watchGameState = () => {
|
||||||
console.log("Ping matchTermitation")
|
console.log("watchGameState");
|
||||||
if (gameState.matchAbort || gameState.matchEnded)
|
if (gameState) { // trigger Svelte reactivity
|
||||||
|
gameState.matchStarted = gameState.matchStarted;
|
||||||
|
gameState.matchEnded = gameState.matchEnded;
|
||||||
|
gameState.matchAborted = gameState.matchAborted;
|
||||||
|
}
|
||||||
|
if (gameState.matchAborted || gameState.matchEnded)
|
||||||
{
|
{
|
||||||
clearInterval(idOfIntevalCheckTerminationOfTheMatch);
|
clearInterval(watchGameStateInterval);
|
||||||
console.log("matchTermitation was called")
|
console.log("watchGameState, end");
|
||||||
showWaitPage = false
|
|
||||||
gameState.matchAbort ?
|
|
||||||
errorMessageWhenAttemptingToGetATicket = "The match has been aborted"
|
|
||||||
: errorMessageWhenAttemptingToGetATicket = "The match is finished !"
|
|
||||||
gameState.matchAbort ? showError = true : showMatchEnded = true;
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resetPage();
|
resetPage();
|
||||||
errorMessageWhenAttemptingToGetATicket = "";
|
console.log("watchGameState : setTimeout");
|
||||||
isThereAnyInvitation = false;
|
|
||||||
invitations = []; // ???
|
|
||||||
console.log("matchTermitation : setTimeout")
|
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const switchToGameOptions = () => {
|
||||||
const showOptions = () => {
|
showGameOptions = true;
|
||||||
showGameOption = true
|
showInvitations = false;
|
||||||
showInvitations = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const showInvitation = async() => {
|
const fetchInvitations = async() => {
|
||||||
showGameOption = false;
|
showGameOptions = false;
|
||||||
showInvitations = true;
|
showInvitations = true;
|
||||||
invitations = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/invitations`)
|
invitations = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/invitations`)
|
||||||
.then(x => x.json())
|
.then(x => x.json());
|
||||||
invitations.length !== 0 ? isThereAnyInvitation = true : isThereAnyInvitation = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const rejectInvitation = async(invitation) => {
|
const rejectInvitation = async(invitation) => {
|
||||||
@@ -156,46 +156,30 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(x => x.json())
|
.then(x => x.json())
|
||||||
.catch(error => console.log(error))
|
.catch(error => console.log(error));
|
||||||
showInvitation()
|
fetchInvitations();
|
||||||
}
|
}
|
||||||
|
|
||||||
const acceptInvitation = async(invitation : any) => {
|
const acceptInvitation = async(invitation : any) =>
|
||||||
|
{
|
||||||
const res = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/accept`, {
|
const res = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/accept`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { 'Content-Type': 'application/json'},
|
headers: { 'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
token : invitation.token
|
token : invitation.token
|
||||||
})
|
})
|
||||||
})
|
}).catch(error => console.log(error));
|
||||||
.then(x => x.json())
|
|
||||||
.catch(error => {
|
|
||||||
console.log(error)
|
|
||||||
})
|
|
||||||
if (res.status === 200)
|
|
||||||
{
|
|
||||||
showInvitation()
|
|
||||||
initGameForInvitedPlayer(invitation)
|
|
||||||
}
|
|
||||||
//Au final c'est utile !
|
|
||||||
|
|
||||||
initGameForInvitedPlayer(invitation) // Luke: normal de initGameForInvitedPlayer() sur un "res.status" different de 200 ?
|
if (res && res.ok) {
|
||||||
|
initGameForInvitedPlayer(invitation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function leaveMatch() {
|
function leaveMatch() {
|
||||||
|
clearInterval(watchGameStateInterval);
|
||||||
resetPage();
|
resetPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
function resetPage() {
|
|
||||||
hiddenGame = true;
|
|
||||||
optionsAreNotSet = true
|
|
||||||
showError = false;
|
|
||||||
showMatchEnded = false;
|
|
||||||
options.reset();
|
|
||||||
options.playerOneUsername = user.username;
|
|
||||||
pong.destroy();
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Header />
|
<Header />
|
||||||
@@ -203,47 +187,61 @@
|
|||||||
Might become useless after CSS rework. -->
|
Might become useless after CSS rework. -->
|
||||||
<div id="game_page">
|
<div id="game_page">
|
||||||
|
|
||||||
{#if showMatchEnded === true}
|
{#if showError}
|
||||||
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
<p>{errorMessageWhenAttemptingToGetATicket}</p>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if showError === true}
|
|
||||||
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Error</legend>
|
<legend>Error</legend>
|
||||||
<p>{errorMessageWhenAttemptingToGetATicket}</p>
|
<p>{errorMessage}</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if !hiddenGame}
|
||||||
|
{#if gameState.matchEnded}
|
||||||
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
|
<p>The match is finished !</p>
|
||||||
|
</div>
|
||||||
|
{:else if gameState.matchAborted}
|
||||||
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
|
<p>The match has been aborted</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div id="canvas_container" hidden={hiddenGame}>
|
<div id="canvas_container" hidden={hiddenGame}>
|
||||||
<canvas id={gameAreaId}/>
|
<canvas id={gameAreaId}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !hiddenGame}
|
{#if !hiddenGame}
|
||||||
<div id="div_game">
|
{#if gameState.matchStarted && !gameState.matchEnded}
|
||||||
<button id="pong_button" on:click={leaveMatch}>forfeit</button>
|
<div class="div_game">
|
||||||
|
<button class="pong_button" on:click={leaveMatch}>forfeit</button>
|
||||||
</div>
|
</div>
|
||||||
|
{:else if !gameState.matchStarted}
|
||||||
|
<div class="div_game">
|
||||||
|
<button class="pong_button" on:click={leaveMatch}>leave matchmaking</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
{#if showWaitPage === true}
|
{#if showWaitPage}
|
||||||
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Connecting to the game...</legend>
|
<legend>Connecting to the game...</legend>
|
||||||
<p>{waitingMessage}</p>
|
<p>Please wait...</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
{#if optionsAreNotSet}
|
{#if optionsAreNotSet}
|
||||||
{#if showGameOption === true}
|
{#if showGameOptions}
|
||||||
<div id="game_option">
|
<div id="game_option">
|
||||||
<div id="div_game">
|
<div class="div_game">
|
||||||
<button id="pong_button" on:click={showInvitation}>Show invitations</button>
|
<button class="pong_button" on:click={fetchInvitations}>Show invitations</button>
|
||||||
<fieldset>
|
<fieldset in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
<legend>game options</legend>
|
<legend>game options</legend>
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
|
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
|
||||||
@@ -264,7 +262,7 @@
|
|||||||
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
|
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
|
||||||
<label for="moving_walls">Invite a friend</label>
|
<label for="moving_walls">Invite a friend</label>
|
||||||
</div>
|
</div>
|
||||||
{#if options.isSomeoneIsInvited === true}
|
{#if options.isSomeoneIsInvited}
|
||||||
<select bind:value={options.playerTwoUsername}>
|
<select bind:value={options.playerTwoUsername}>
|
||||||
{#each allUsers as user }
|
{#each allUsers as user }
|
||||||
<option value={user.username}>{user.username}</option>
|
<option value={user.username}>{user.username}</option>
|
||||||
@@ -272,7 +270,7 @@
|
|||||||
</select>
|
</select>
|
||||||
{/if}
|
{/if}
|
||||||
<div>
|
<div>
|
||||||
<button id="pong_button" on:click={initGame}>PLAY</button>
|
<button class="pong_button" on:click={initGame}>PLAY</button>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@@ -280,27 +278,24 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showInvitations}
|
{#if showInvitations}
|
||||||
<div id="invitations_options" in:fly="{{ y: 10, duration: 1000 }}">
|
<div class="div_game">
|
||||||
<div id="div_game">
|
<button class="pong_button" on:click={switchToGameOptions}>Play a Game</button>
|
||||||
<button id="pong_button" on:click={showOptions}>Play a Game</button>
|
<fieldset in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
<fieldset>
|
<legend>invitations</legend>
|
||||||
<legend>Current invitation(s)</legend>
|
<button class="pong_button" on:click={fetchInvitations}>Reload</button>
|
||||||
{#if isThereAnyInvitation}
|
{#if invitations.length !== 0}
|
||||||
{#each invitations as invitation }
|
{#each invitations as invitation}
|
||||||
<div>
|
<div>
|
||||||
{invitation.playerOneUsername} has invited you to play a pong !
|
{invitation.playerOneUsername} has invited you to play a pong !
|
||||||
<button id="pong_button" on:click={() => acceptInvitation(invitation)}>V</button>
|
<button class="pong_button" on:click={() => acceptInvitation(invitation)}>V</button>
|
||||||
<button id="pong_button" on:click={() => rejectInvitation(invitation)}>X</button>
|
<button class="pong_button" on:click={() => rejectInvitation(invitation)}>X</button>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{:else}
|
||||||
{#if isThereAnyInvitation === false}
|
|
||||||
<p>Currently, no one asked to play with you.</p>
|
<p>Currently, no one asked to play with you.</p>
|
||||||
<button id="pong_button" on:click={showInvitation}>Reload</button>
|
|
||||||
{/if}
|
{/if}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -319,6 +314,7 @@
|
|||||||
}
|
}
|
||||||
#game_page {
|
#game_page {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
background-color: #222425;
|
background-color: #222425;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -339,22 +335,21 @@ canvas {
|
|||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#div_game {
|
.div_game {
|
||||||
margin-top: 20px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: "Bit5x3";
|
font-family: "Bit5x3";
|
||||||
color: rgb(245, 245, 245);
|
color: rgb(245, 245, 245);
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
}
|
}
|
||||||
#div_game fieldset {
|
.div_game fieldset {
|
||||||
max-width: 50vw;
|
max-width: 50vw;
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
#div_game fieldset div {
|
.div_game fieldset div {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
#pong_button {
|
.pong_button {
|
||||||
font-family: "Bit5x3";
|
font-family: "Bit5x3";
|
||||||
color: rgb(245, 245, 245);
|
color: rgb(245, 245, 245);
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
@@ -362,18 +357,4 @@ canvas {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#users_name { /* UNUSED */
|
|
||||||
text-align: center;
|
|
||||||
font-family: "Bit5x3";
|
|
||||||
color: rgb(245, 245, 245);
|
|
||||||
font-size: x-large;
|
|
||||||
}
|
|
||||||
#error_notification { /* UNUSED */
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
font-family: "Bit5x3";
|
|
||||||
color: rgb(143, 19, 19);
|
|
||||||
font-size: x-large;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import * as pongSpectator from "./client/pongSpectator";
|
import * as pongSpectator from "./client/pongSpectator";
|
||||||
import { gameState } from "./client/ws";
|
import { gameState } from "./client/ws";
|
||||||
import { gameSessionIdPLACEHOLDER } from "./shared_js/constants";
|
|
||||||
|
|
||||||
//user's stuff
|
//user's stuff
|
||||||
let user;
|
let user;
|
||||||
@@ -17,79 +16,71 @@
|
|||||||
//Game's stuff client side only
|
//Game's stuff client side only
|
||||||
const gameAreaId = "game_area";
|
const gameAreaId = "game_area";
|
||||||
let sound = "off";
|
let sound = "off";
|
||||||
// const dummyMatchList = [
|
|
||||||
// {
|
|
||||||
// gameSessionId: gameSessionIdPLACEHOLDER,
|
|
||||||
// matchOptions: pongSpectator.MatchOptions.noOption,
|
|
||||||
// playerOneUsername: "toto",
|
|
||||||
// playerTwoUsername: "bruno",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// gameSessionId: gameSessionIdPLACEHOLDER,
|
|
||||||
// matchOptions: pongSpectator.MatchOptions.multiBalls,
|
|
||||||
// playerOneUsername: "pl1",
|
|
||||||
// playerTwoUsername: "pl2",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// gameSessionId: "id6543",
|
|
||||||
// matchOptions: pongSpectator.MatchOptions.movingWalls | pongSpectator.MatchOptions.multiBalls,
|
|
||||||
// playerOneUsername: "bertand",
|
|
||||||
// playerTwoUsername: "cassandre",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// gameSessionId: "id3452",
|
|
||||||
// matchOptions: pongSpectator.MatchOptions.multiBalls,
|
|
||||||
// playerOneUsername: "madeleine",
|
|
||||||
// playerTwoUsername: "jack",
|
|
||||||
// },
|
|
||||||
// ];
|
|
||||||
let matchList = [];
|
let matchList = [];
|
||||||
|
|
||||||
//html boolean for pages
|
//html boolean for pages
|
||||||
let hiddenGame = true;
|
let hiddenGame = true;
|
||||||
let hiddenMatchList = false;
|
|
||||||
|
|
||||||
|
let watchGameStateInterval;
|
||||||
|
const watchGameStateIntervalRate = 142;
|
||||||
|
|
||||||
onMount( async() => {
|
onMount( async() => {
|
||||||
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
|
||||||
.then( x => x.json() );
|
.then( x => x.json() );
|
||||||
allUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/all`)
|
allUsers = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user/all`)
|
||||||
.then( x => x.json() );
|
.then( x => x.json() );
|
||||||
// WIP: fetch for match list here
|
|
||||||
const responseForMatchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
|
const responseForMatchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
|
||||||
const jsonForMatchList = await responseForMatchList.json();
|
const jsonForMatchList = await responseForMatchList.json();
|
||||||
matchList = jsonForMatchList;
|
matchList = jsonForMatchList;
|
||||||
console.log("matchList");
|
|
||||||
if (matchList.length <= 0)
|
|
||||||
hiddenMatchList = true;
|
|
||||||
console.log(matchList);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy( async() => {
|
onDestroy( async() => {
|
||||||
|
clearInterval(watchGameStateInterval);
|
||||||
pongSpectator.destroy();
|
pongSpectator.destroy();
|
||||||
})
|
})
|
||||||
|
|
||||||
async function initGameSpectator(gameSessionId: string, matchOptions: pongSpectator.MatchOptions) {
|
async function initGameSpectator(gameSessionId: string, matchOptions: pongSpectator.MatchOptions)
|
||||||
|
{
|
||||||
|
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
|
||||||
pongSpectator.init(matchOptions, sound, gameAreaId, gameSessionId);
|
pongSpectator.init(matchOptions, sound, gameAreaId, gameSessionId);
|
||||||
hiddenGame = false;
|
hiddenGame = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const watchGameState = () => {
|
||||||
|
console.log("watchGameState")
|
||||||
|
if (gameState) { // trigger Svelte reactivity
|
||||||
|
gameState.matchStarted = gameState.matchStarted;
|
||||||
|
gameState.matchEnded = gameState.matchEnded;
|
||||||
|
gameState.matchAborted = gameState.matchAborted;
|
||||||
|
}
|
||||||
|
if (gameState.matchAborted || gameState.matchEnded)
|
||||||
|
{
|
||||||
|
clearInterval(watchGameStateInterval);
|
||||||
|
console.log("watchGameState, end")
|
||||||
|
setTimeout(() => {
|
||||||
|
resetPage();
|
||||||
|
console.log("watchGameState : setTimeout")
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function leaveMatch() {
|
function leaveMatch() {
|
||||||
|
clearInterval(watchGameStateInterval);
|
||||||
resetPage();
|
resetPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
async function resetPage() {
|
async function resetPage() {
|
||||||
hiddenGame = true;
|
hiddenGame = true;
|
||||||
pongSpectator.destroy();
|
pongSpectator.destroy();
|
||||||
// WIP: fetch for match list here
|
fetchMatchList();
|
||||||
|
};
|
||||||
|
|
||||||
|
async function fetchMatchList() {
|
||||||
matchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
|
matchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
|
||||||
.then( x => x.json() );
|
.then( x => x.json() );
|
||||||
console.log("matchList");
|
|
||||||
if (matchList.length <= 0)
|
|
||||||
hiddenMatchList = true;
|
|
||||||
console.log(matchList);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@@ -98,18 +89,33 @@
|
|||||||
Might become useless after CSS rework. -->
|
Might become useless after CSS rework. -->
|
||||||
<div id="game_page">
|
<div id="game_page">
|
||||||
|
|
||||||
|
{#if !hiddenGame}
|
||||||
|
{#if gameState.matchEnded}
|
||||||
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
|
<p>The match is finished !</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div id="canvas_container" hidden={hiddenGame}>
|
<div id="canvas_container" hidden={hiddenGame}>
|
||||||
<canvas id={gameAreaId}/>
|
<canvas id={gameAreaId}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if !hiddenGame}
|
||||||
|
{#if !gameState.matchEnded}
|
||||||
|
<div class="div_game">
|
||||||
|
<button class="pong_button" on:click={leaveMatch}>leave</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
{#if hiddenGame}
|
{#if hiddenGame}
|
||||||
<div id="div_game">
|
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||||
<div id="game_options">
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{#if hiddenMatchList}
|
|
||||||
<legend>no match available</legend>
|
|
||||||
{:else}
|
|
||||||
<legend>options</legend>
|
<legend>options</legend>
|
||||||
|
<button class="pong_button" on:click={fetchMatchList}>Reload</button>
|
||||||
<div>
|
<div>
|
||||||
<p>sound :</p>
|
<p>sound :</p>
|
||||||
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
|
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
|
||||||
@@ -117,19 +123,16 @@
|
|||||||
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
|
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
|
||||||
<label for="sound_off">off</label>
|
<label for="sound_off">off</label>
|
||||||
</div>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{#if matchList.length !== 0}
|
||||||
<menu id="match_list">
|
<menu id="match_list">
|
||||||
{#each matchList as match}
|
{#each matchList as match}
|
||||||
<MatchListElem match={match} on:click={(e) => initGameSpectator(match.gameServerIdOfTheMatch, match.gameOptions)} />
|
<MatchListElem match={match} on:click={(e) => initGameSpectator(match.gameServerIdOfTheMatch, match.gameOptions)} />
|
||||||
{/each}
|
{/each}
|
||||||
</menu>
|
</menu>
|
||||||
{/if}
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<div id="div_game">
|
<p>no match ongoing</p>
|
||||||
<button id="pong_button" on:click={leaveMatch}>leave match</button>
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -147,8 +150,10 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#game_page {
|
#game_page {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
background-color: #222425;
|
background-color: #222425;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -157,37 +162,43 @@
|
|||||||
#canvas_container {
|
#canvas_container {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
/* border: dashed rgb(245, 245, 245) 5px; */
|
||||||
|
/* max-height: 80vh; */
|
||||||
|
/* overflow: hidden; */
|
||||||
}
|
}
|
||||||
canvas {
|
canvas {
|
||||||
|
/* background-color: #ff0000; */
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
max-width: 75vw;
|
max-width: 75vw;
|
||||||
|
/* max-height: 100vh; */
|
||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#div_game {
|
.div_game {
|
||||||
margin-top: 20px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: "Bit5x3";
|
font-family: "Bit5x3";
|
||||||
color: rgb(245, 245, 245);
|
color: rgb(245, 245, 245);
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
}
|
}
|
||||||
#div_game fieldset {
|
.div_game fieldset {
|
||||||
max-width: 50vw;
|
max-width: 50vw;
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
#div_game fieldset div {
|
.div_game fieldset div {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
#match_list {
|
.pong_button {
|
||||||
font-family: 'Courier New', Courier, monospace;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
#pong_button {
|
|
||||||
font-family: "Bit5x3";
|
font-family: "Bit5x3";
|
||||||
color: rgb(245, 245, 245);
|
color: rgb(245, 245, 245);
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#match_list {
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -27,30 +27,24 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<Header />
|
<Header />
|
||||||
|
<br />
|
||||||
|
|
||||||
<div class="container">
|
<div class="principal-div">
|
||||||
<div class="row">
|
<table class="stats-table">
|
||||||
<div class="col-12">
|
|
||||||
<h1>Ranking</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th>#</th>
|
||||||
<th scope="col">Username</th>
|
<th>Username</th>
|
||||||
<th scope="col">Win</th>
|
<th>Win</th>
|
||||||
<th scope="col">Lose</th>
|
<th>Lose</th>
|
||||||
<th scope="col">Draw</th>
|
<th>Draw</th>
|
||||||
<th scope="col">Games Played</th>
|
<th>Games Played</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each allUsers as user, i}
|
{#each allUsers as user, i}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{i + 1}</th>
|
<th>{i + 1}</th>
|
||||||
{#if user.username === currentUser.username}
|
{#if user.username === currentUser.username}
|
||||||
<td><b>You ({user.username})</b></td>
|
<td><b>You ({user.username})</b></td>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -64,11 +58,47 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
.principal-div {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.stats-table {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-family: sans-serif;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table thead tr {
|
||||||
|
background-color: #618174;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table th,
|
||||||
|
.stats-table td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table tbody tr {
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table tbody tr:nth-of-type(even) {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table tbody tr:last-of-type {
|
||||||
|
border-bottom: 2px solid #618174;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-table tbody tr.active-row {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #618174;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,26 +2,37 @@
|
|||||||
import * as c from "./constants.js"
|
import * as c from "./constants.js"
|
||||||
|
|
||||||
// export const soundPongArr: HTMLAudioElement[] = [];
|
// export const soundPongArr: HTMLAudioElement[] = [];
|
||||||
export const soundPongArr: HTMLAudioElement[] = [
|
export let muteFlag: boolean;
|
||||||
new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+1+".ogg"),
|
export const soundPongArr: HTMLAudioElement[] = [];
|
||||||
new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+2+".ogg")
|
export let soundRoblox: HTMLAudioElement;
|
||||||
];
|
|
||||||
export const soundRoblox = new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/roblox-oof.ogg");
|
|
||||||
|
|
||||||
export function initAudio(sound: string)
|
export function initAudio(sound: string)
|
||||||
{
|
{
|
||||||
let muteFlag: boolean;
|
soundPongArr.length = 0;
|
||||||
|
soundRoblox = null;
|
||||||
|
|
||||||
if (sound === "on") {
|
if (sound === "on") {
|
||||||
muteFlag = false;
|
muteFlag = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
muteFlag = true;
|
muteFlag = true;
|
||||||
|
return; // Could be changed
|
||||||
|
/*
|
||||||
|
Stop initAudio() here because in the current state of the game
|
||||||
|
there no way to change muteFlag after game start.
|
||||||
|
If it becomes an option,
|
||||||
|
we should continue initAudio() regardless of the muteFlag.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
soundPongArr.push(new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+1+".ogg"));
|
||||||
|
soundPongArr.push(new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/pong/"+2+".ogg"));
|
||||||
soundPongArr.forEach((value) => {
|
soundPongArr.forEach((value) => {
|
||||||
value.volume = c.soundRobloxVolume;
|
value.volume = c.soundRobloxVolume;
|
||||||
value.muted = muteFlag;
|
value.muted = muteFlag;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
soundRoblox = new Audio("http://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/sound/roblox-oof.ogg");
|
||||||
soundRoblox.volume = c.soundRobloxVolume;
|
soundRoblox.volume = c.soundRobloxVolume;
|
||||||
soundRoblox.muted = muteFlag;
|
soundRoblox.muted = muteFlag;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export class GameArea {
|
|||||||
handleInputInterval: number = 0;
|
handleInputInterval: number = 0;
|
||||||
gameLoopInterval: number = 0;
|
gameLoopInterval: number = 0;
|
||||||
drawLoopInterval: number = 0;
|
drawLoopInterval: number = 0;
|
||||||
|
timeoutArr: number[] = [];
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
constructor(canvas_id: string) {
|
constructor(canvas_id: string) {
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ export class InitOptions {
|
|||||||
isInvitedPerson = false;
|
isInvitedPerson = false;
|
||||||
playerOneUsername = "";
|
playerOneUsername = "";
|
||||||
playerTwoUsername = "";
|
playerTwoUsername = "";
|
||||||
reset() {
|
reset(playerOneUsername: string) {
|
||||||
this.sound = "off";
|
this.sound = "off";
|
||||||
this.multi_balls = false;
|
this.multi_balls = false;
|
||||||
this.moving_walls = false;
|
this.moving_walls = false;
|
||||||
this.isSomeoneIsInvited = false;
|
this.isSomeoneIsInvited = false;
|
||||||
this.isInvitedPerson = false;
|
this.isInvitedPerson = false;
|
||||||
this.playerOneUsername = "";
|
this.playerOneUsername = playerOneUsername;
|
||||||
this.playerTwoUsername = "";
|
this.playerTwoUsername = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { Vector, VectorInteger } from "../../shared_js/class/Vector.js";
|
import { Vector, VectorInteger } from "../../shared_js/class/Vector.js";
|
||||||
import type { GraphicComponent } from "../../shared_js/class/interface.js";
|
import type { GraphicComponent } from "../../shared_js/class/interface.js";
|
||||||
import { Rectangle, MovingRectangle, Racket, Ball } from "../../shared_js/class/Rectangle.js";
|
import { Rectangle, MovingRectangle, Racket, Ball } from "../../shared_js/class/Rectangle.js";
|
||||||
import { soundPongArr } from "../audio.js"
|
import { muteFlag, soundPongArr } from "../audio.js"
|
||||||
import { random } from "../utils.js";
|
import { random } from "../utils.js";
|
||||||
|
|
||||||
function updateRectangle(this: RectangleClient) {
|
function updateRectangle(this: RectangleClient) {
|
||||||
@@ -70,6 +70,7 @@ export class BallClient extends Ball implements GraphicComponent {
|
|||||||
color: string;
|
color: string;
|
||||||
update: () => void;
|
update: () => void;
|
||||||
clear: (pos?: VectorInteger) => void;
|
clear: (pos?: VectorInteger) => void;
|
||||||
|
soundSwitch = false;
|
||||||
constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number,
|
constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number,
|
||||||
ctx: CanvasRenderingContext2D, color: string)
|
ctx: CanvasRenderingContext2D, color: string)
|
||||||
{
|
{
|
||||||
@@ -81,9 +82,14 @@ export class BallClient extends Ball implements GraphicComponent {
|
|||||||
}
|
}
|
||||||
bounce(collider?: Rectangle) {
|
bounce(collider?: Rectangle) {
|
||||||
this._bounceAlgo(collider);
|
this._bounceAlgo(collider);
|
||||||
let i = Math.floor(random(0, soundPongArr.length));
|
if (!muteFlag)
|
||||||
soundPongArr[ i ].play();
|
{
|
||||||
console.log(`sound_i=${i}`); // debug log
|
this.soundSwitch = !this.soundSwitch;
|
||||||
|
soundPongArr[this.soundSwitch ? 1 : 0].play();
|
||||||
|
// let i = Math.floor(random(0, soundPongArr.length));
|
||||||
|
// soundPongArr[ i ].play();
|
||||||
|
// console.log(`sound_i=${i}`); // debug log
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,15 +34,28 @@ export function initBase(matchOptions: en.MatchOptions, sound: string, gameAreaI
|
|||||||
|
|
||||||
export function destroyBase()
|
export function destroyBase()
|
||||||
{
|
{
|
||||||
if (pong)
|
if (socket && (socket.OPEN || socket.CONNECTING)) {
|
||||||
{
|
|
||||||
clearInterval(pong.handleInputInterval);
|
|
||||||
clearInterval(pong.gameLoopInterval);
|
|
||||||
clearInterval(pong.drawLoopInterval);
|
|
||||||
setPong(null);
|
|
||||||
}
|
|
||||||
if (socket && socket.OPEN) {
|
|
||||||
socket.close();
|
socket.close();
|
||||||
}
|
}
|
||||||
|
if (pong)
|
||||||
|
{
|
||||||
|
pong.timeoutArr.forEach((value) => {
|
||||||
|
clearTimeout(value);
|
||||||
|
});
|
||||||
|
pong.timeoutArr = [];
|
||||||
|
|
||||||
|
clearInterval(pong.handleInputInterval);
|
||||||
|
pong.handleInputInterval = null;
|
||||||
|
|
||||||
|
clearInterval(pong.gameLoopInterval);
|
||||||
|
pong.gameLoopInterval = null;
|
||||||
|
|
||||||
|
clearInterval(pong.drawLoopInterval);
|
||||||
|
pong.drawLoopInterval = null;
|
||||||
|
|
||||||
|
setPong(null);
|
||||||
|
}
|
||||||
|
setGc(null);
|
||||||
|
setMatchOptions(null);
|
||||||
resetGameState();
|
resetGameState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
|
|
||||||
import * as c from "./constants.js"
|
import * as c from "./constants.js"
|
||||||
|
import type * as en from "../shared_js/enums.js"
|
||||||
import { handleInput } from "./handleInput.js";
|
import { handleInput } from "./handleInput.js";
|
||||||
import { gameLoop } from "./gameLoop.js"
|
import { gameLoop } from "./gameLoop.js"
|
||||||
import { drawLoop } from "./draw.js";
|
import { drawLoop } from "./draw.js";
|
||||||
import { countdown } from "./utils.js";
|
import { countdown } from "./utils.js";
|
||||||
import { initWebSocket } from "./ws.js";
|
import { gameState, initWebSocket } from "./ws.js";
|
||||||
import type { InitOptions } from "./class/InitOptions.js";
|
import type { InitOptions } from "./class/InitOptions.js";
|
||||||
export { InitOptions } from "./class/InitOptions.js";
|
export { InitOptions } from "./class/InitOptions.js";
|
||||||
import { initBase, destroyBase, computeMatchOptions } from "./init.js";
|
import { initBase, destroyBase, computeMatchOptions } from "./init.js";
|
||||||
export { computeMatchOptions } from "./init.js";
|
export { computeMatchOptions } from "./init.js";
|
||||||
|
|
||||||
/* TODO: A way to delay the init of variables, but still use "const" not "let" ? */
|
|
||||||
import { pong, gc } from "./global.js"
|
import { pong, gc } from "./global.js"
|
||||||
import { setStartFunction } from "./global.js"
|
import { setStartFunction } from "./global.js"
|
||||||
|
|
||||||
let abortControllerKeydown: AbortController;
|
let abortControllerKeydown: AbortController;
|
||||||
let abortControllerKeyup: AbortController;
|
let abortControllerKeyup: AbortController;
|
||||||
|
|
||||||
export function init(options: InitOptions, gameAreaId: string, token: string)
|
export function init(matchOptions: en.MatchOptions, options: InitOptions, gameAreaId: string, token: string)
|
||||||
{
|
{
|
||||||
const matchOptions = computeMatchOptions(options);
|
|
||||||
initBase(matchOptions, options.sound, gameAreaId);
|
initBase(matchOptions, options.sound, gameAreaId);
|
||||||
|
|
||||||
setStartFunction(start);
|
setStartFunction(start);
|
||||||
@@ -47,11 +46,12 @@ export function destroy()
|
|||||||
function start()
|
function start()
|
||||||
{
|
{
|
||||||
gc.text1.pos.assign(c.w*0.5, c.h*0.75);
|
gc.text1.pos.assign(c.w*0.5, c.h*0.75);
|
||||||
countdown(c.matchStartDelay/1000, (count: number) => {
|
const countdownArr = countdown(c.matchStartDelay, 1000, (count: number) => {
|
||||||
gc.text1.clear();
|
gc.text1.clear();
|
||||||
gc.text1.text = `${count}`;
|
gc.text1.text = `${count/1000}`;
|
||||||
gc.text1.update();
|
gc.text1.update();
|
||||||
}, start_after_countdown);
|
}, start_after_countdown);
|
||||||
|
pong.timeoutArr = pong.timeoutArr.concat(countdownArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
function start_after_countdown()
|
function start_after_countdown()
|
||||||
@@ -66,7 +66,7 @@ function start_after_countdown()
|
|||||||
abortControllerKeyup = new AbortController();
|
abortControllerKeyup = new AbortController();
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'keyup',
|
'keyup',
|
||||||
(e) => { pong.deleteKey(e.key);},
|
(e) => { pong.deleteKey(e.key); },
|
||||||
{signal: abortControllerKeyup.signal}
|
{signal: abortControllerKeyup.signal}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
|
|
||||||
export * from "../shared_js/utils.js"
|
export * from "../shared_js/utils.js"
|
||||||
|
|
||||||
export function countdown(count: number, callback?: (count: number) => void, endCallback?: () => void)
|
export function countdown(count: number, step: number, callback: (count: number) => void, endCallback?: () => void) : number[]
|
||||||
{
|
{
|
||||||
|
const timeoutArr: number[] = [];
|
||||||
|
|
||||||
|
if (endCallback) {
|
||||||
|
timeoutArr.push( window.setTimeout(endCallback, count) );
|
||||||
|
}
|
||||||
|
|
||||||
|
let reverseCount = 0;
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
timeoutArr.push( window.setTimeout((count: number) => {
|
||||||
console.log("countdown ", count);
|
console.log("countdown ", count);
|
||||||
if (count > 0) {
|
|
||||||
if (callback) {
|
|
||||||
callback(count);
|
callback(count);
|
||||||
|
}, reverseCount, count)
|
||||||
|
);
|
||||||
|
count -= step;
|
||||||
|
reverseCount += step;
|
||||||
}
|
}
|
||||||
setTimeout(countdown, 1000, --count, callback, endCallback);
|
|
||||||
}
|
return timeoutArr;
|
||||||
else if (endCallback) {
|
|
||||||
endCallback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,20 @@ import * as en from "../shared_js/enums.js"
|
|||||||
import * as msg from "./message.js";
|
import * as msg from "./message.js";
|
||||||
import type { RacketClient } from "./class/RectangleClient.js";
|
import type { RacketClient } from "./class/RectangleClient.js";
|
||||||
import { repeatInput } from "./handleInput.js";
|
import { repeatInput } from "./handleInput.js";
|
||||||
import { soundRoblox } from "./audio.js"
|
import { muteFlag, soundRoblox } from "./audio.js"
|
||||||
import { sleep } from "./utils.js";
|
import { sleep } from "./utils.js";
|
||||||
import { Vector, VectorInteger } from "../shared_js/class/Vector.js";
|
import { Vector, VectorInteger } from "../shared_js/class/Vector.js";
|
||||||
|
|
||||||
export const gameState = {
|
export const gameState = {
|
||||||
|
matchStarted: false,
|
||||||
matchEnded: false,
|
matchEnded: false,
|
||||||
matchAbort: false
|
matchAborted: false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resetGameState() {
|
export function resetGameState() {
|
||||||
|
gameState.matchStarted = false;
|
||||||
gameState.matchEnded = false;
|
gameState.matchEnded = false;
|
||||||
gameState.matchAbort = false;
|
gameState.matchAborted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClientInfo {
|
class ClientInfo {
|
||||||
@@ -36,7 +38,7 @@ class ClientInfoSpectator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wsUrl = "ws://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/pong";
|
const wsUrl = "ws://" + process.env.WEBSITE_HOST + ":" + process.env.WEBSITE_PORT + "/pong";
|
||||||
export let socket: WebSocket; /* TODO: A way to still use "const" not "let" ? */
|
export let socket: WebSocket;
|
||||||
export const clientInfo = new ClientInfo();
|
export const clientInfo = new ClientInfo();
|
||||||
export const clientInfoSpectator = new ClientInfoSpectator(); // WIP, could refactor this
|
export const clientInfoSpectator = new ClientInfoSpectator(); // WIP, could refactor this
|
||||||
|
|
||||||
@@ -99,12 +101,13 @@ function preMatchListener(this: WebSocket, event: MessageEvent)
|
|||||||
msg.matchmakingComplete();
|
msg.matchmakingComplete();
|
||||||
break;
|
break;
|
||||||
case en.EventTypes.matchStart:
|
case en.EventTypes.matchStart:
|
||||||
|
gameState.matchStarted = true;
|
||||||
socket.removeEventListener("message", preMatchListener);
|
socket.removeEventListener("message", preMatchListener);
|
||||||
socket.addEventListener("message", inGameListener);
|
socket.addEventListener("message", inGameListener);
|
||||||
startFunction();
|
startFunction();
|
||||||
break;
|
break;
|
||||||
case en.EventTypes.matchAbort:
|
case en.EventTypes.matchAbort:
|
||||||
gameState.matchAbort = true;
|
gameState.matchAborted = true;
|
||||||
socket.removeEventListener("message", preMatchListener);
|
socket.removeEventListener("message", preMatchListener);
|
||||||
msg.matchAbort();
|
msg.matchAbort();
|
||||||
break;
|
break;
|
||||||
@@ -195,12 +198,15 @@ function gameUpdate(data: ev.EventGameUpdate)
|
|||||||
function scoreUpdate(data: ev.EventScoreUpdate)
|
function scoreUpdate(data: ev.EventScoreUpdate)
|
||||||
{
|
{
|
||||||
// console.log("scoreUpdate");
|
// console.log("scoreUpdate");
|
||||||
|
if (!muteFlag)
|
||||||
|
{
|
||||||
if (clientInfo.side === en.PlayerSide.left && data.scoreRight > gc.scoreRight.value) {
|
if (clientInfo.side === en.PlayerSide.left && data.scoreRight > gc.scoreRight.value) {
|
||||||
soundRoblox.play();
|
soundRoblox.play();
|
||||||
}
|
}
|
||||||
else if (clientInfo.side === en.PlayerSide.right && data.scoreLeft > gc.scoreLeft.value) {
|
else if (clientInfo.side === en.PlayerSide.right && data.scoreLeft > gc.scoreLeft.value) {
|
||||||
soundRoblox.play();
|
soundRoblox.play();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
gc.scoreLeft.value = data.scoreLeft;
|
gc.scoreLeft.value = data.scoreLeft;
|
||||||
gc.scoreRight.value = data.scoreRight;
|
gc.scoreRight.value = data.scoreRight;
|
||||||
}
|
}
|
||||||
@@ -242,6 +248,7 @@ export function preMatchListenerSpectator(this: WebSocket, event: MessageEvent)
|
|||||||
const data: ev.ServerEvent = JSON.parse(event.data);
|
const data: ev.ServerEvent = JSON.parse(event.data);
|
||||||
if (data.type === en.EventTypes.matchStart)
|
if (data.type === en.EventTypes.matchStart)
|
||||||
{
|
{
|
||||||
|
gameState.matchStarted = true;
|
||||||
socket.removeEventListener("message", preMatchListenerSpectator);
|
socket.removeEventListener("message", preMatchListenerSpectator);
|
||||||
socket.addEventListener("message", inGameListenerSpectator);
|
socket.addEventListener("message", inGameListenerSpectator);
|
||||||
socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientSpectatorReady) ));
|
socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientSpectatorReady) ));
|
||||||
@@ -322,10 +329,5 @@ function matchEndSpectator(data: ev.EventMatchEnd)
|
|||||||
console.log("matchEndSpectator");
|
console.log("matchEndSpectator");
|
||||||
gameState.matchEnded = true;
|
gameState.matchEnded = true;
|
||||||
socket.close();
|
socket.close();
|
||||||
// WIP
|
|
||||||
/* msg.win();
|
|
||||||
if (data.forfeit) {
|
|
||||||
msg.forfeit(clientInfo.side);
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export enum InputEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum PlayerSide {
|
export enum PlayerSide {
|
||||||
|
noSide = 0,
|
||||||
left = 1,
|
left = 1,
|
||||||
right
|
right
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,11 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
import Layouts from './Chat_layouts.svelte';
|
import Layouts from './Chat_layouts.svelte';
|
||||||
|
import { init_socket } from './Socket_init';
|
||||||
|
|
||||||
export let color = "transparent";
|
export let color = "transparent";
|
||||||
|
|
||||||
/* web sockets with socket.io
|
init_socket();
|
||||||
*/
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import io from 'socket.io-client';
|
|
||||||
const socket = io(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}`, {
|
|
||||||
path: '/chat'
|
|
||||||
});
|
|
||||||
onMount(async => {
|
|
||||||
socket.on('connect', function(){
|
|
||||||
console.log("socket.io connected");
|
|
||||||
});
|
|
||||||
socket.on('disconnect', function(){
|
|
||||||
console.log("socket.io disconnected");
|
|
||||||
});
|
|
||||||
socket.on('connect_error', function(){
|
|
||||||
console.log("socket.io connect_error");
|
|
||||||
});
|
|
||||||
socket.on('connect_timeout', function(){
|
|
||||||
console.log("socket.io connect_timeout");
|
|
||||||
});
|
|
||||||
socket.on('error', function(){
|
|
||||||
console.log("socket.io error");
|
|
||||||
});
|
|
||||||
socket.on('reconnect', function(){
|
|
||||||
console.log("socket.io reconnect");
|
|
||||||
});
|
|
||||||
socket.on('reconnect_attempt', function(){
|
|
||||||
console.log("socket.io reconnect_attempt");
|
|
||||||
});
|
|
||||||
socket.on('reconnecting', function(){
|
|
||||||
console.log("socket.io reconnecting");
|
|
||||||
});
|
|
||||||
socket.on('reconnect_error', function(){
|
|
||||||
console.log("socket.io reconnect_error");
|
|
||||||
});
|
|
||||||
socket.on('reconnect_failed', function(){
|
|
||||||
console.log("socket.io reconnect_failed");
|
|
||||||
});
|
|
||||||
socket.on('ping', function(){
|
|
||||||
console.log("socket.io ping");
|
|
||||||
});
|
|
||||||
socket.on('pong', function(){
|
|
||||||
console.log("socket.io pong");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
import { layout } from './Store_chat';
|
||||||
|
|
||||||
export let color;
|
export let color;
|
||||||
export let layout;
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="{layout} chat_box" style="background-color: {color};">
|
<div class="{$layout} chat_box" style="background-color: {color};">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
import Debug from './tmp_debug.svelte';
|
||||||
|
|
||||||
|
import { layout } from './Store_chat';
|
||||||
import ChatBox from './Chat_box_css.svelte';
|
import ChatBox from './Chat_box_css.svelte';
|
||||||
|
|
||||||
import CloseLayout from './Layout_close.svelte';
|
import CloseLayout from './Layout_close.svelte';
|
||||||
@@ -14,68 +16,75 @@
|
|||||||
import MuteLayout from './Layout_mute.svelte';
|
import MuteLayout from './Layout_mute.svelte';
|
||||||
import UserLayout from './Layout_user.svelte';
|
import UserLayout from './Layout_user.svelte';
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
/* global variables
|
/* global variables
|
||||||
*/
|
*/
|
||||||
export let color;
|
export let color;
|
||||||
let room = "";
|
let room = "";
|
||||||
let admin = false;
|
let admin = false;
|
||||||
let layout = "close";
|
|
||||||
let layouts = ["home", "home"];
|
let layouts = ["home", "home"];
|
||||||
|
|
||||||
/* hold previous version of layout, to go back
|
/* hold previous version of layout, to go back
|
||||||
*/
|
*/
|
||||||
function set_layouts(layout)
|
function set_layouts($layout)
|
||||||
{
|
{
|
||||||
if (layout === "close")
|
console.log("layouts:", layouts);
|
||||||
|
console.log("layout:", $layout);
|
||||||
|
if ($layout.length === 0)
|
||||||
|
layout.set(layouts[0]);
|
||||||
|
else if ($layout === "close")
|
||||||
return;
|
return;
|
||||||
if (layout === layouts[0])
|
else if ($layout === layouts[0])
|
||||||
return;
|
return;
|
||||||
if (layout === layouts[1])
|
else if ($layout === layouts[1])
|
||||||
layouts = [layout, "home"];
|
layouts = [$layout, "home"];
|
||||||
else
|
else
|
||||||
layouts = [layout, layouts[0]];
|
layouts = [$layout, layouts[0]];
|
||||||
|
console.log("- layouts:", layouts);
|
||||||
}
|
}
|
||||||
$: set_layouts(layout);
|
$: set_layouts($layout);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ChatBox layout={layout} color={color}>
|
<ChatBox color={color}>
|
||||||
|
|
||||||
{#if layout === "home"}
|
{#if $layout === "home"}
|
||||||
<HomeLayout bind:layout />
|
<HomeLayout />
|
||||||
|
|
||||||
{:else if layout === "close"}
|
{:else if $layout === "close"}
|
||||||
<CloseLayout bind:layout />
|
<CloseLayout back={layouts[0]} />
|
||||||
|
|
||||||
{:else if layout === "room"}
|
{:else if $layout === "room"}
|
||||||
<RoomLayout bind:layout back={layouts[1]} />
|
<RoomLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "new"}
|
{:else if $layout === "new"}
|
||||||
<NewLayout bind:layout back={layouts[1]} />
|
<NewLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "settings"}
|
{:else if $layout === "settings"}
|
||||||
<SettingsLayout bind:layout back={layouts[1]} />
|
<SettingsLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "room_set"}
|
{:else if $layout === "room_set"}
|
||||||
<RoomsetLayout bind:layout back={layouts[1]} />
|
<RoomsetLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "protected"}
|
{:else if $layout === "protected"}
|
||||||
<ProtectedLayout bind:layout back={layouts[1]} />
|
<ProtectedLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "create"}
|
{:else if $layout === "create"}
|
||||||
<CreateLayout bind:layout back={layouts[1]} />
|
<CreateLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "mute"}
|
{:else if $layout === "mute"}
|
||||||
<MuteLayout bind:layout back={layouts[1]} />
|
<MuteLayout back={layouts[1]} />
|
||||||
|
|
||||||
{:else if layout === "user"}
|
{:else if $layout === "user"}
|
||||||
<UserLayout bind:layout back={layouts[1]} />
|
<UserLayout back={layouts[1]} />
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</ChatBox>
|
</ChatBox>
|
||||||
|
|
||||||
|
<!-- TMP DEBUG -->
|
||||||
|
<Debug bind:layouts />
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
<Button
|
<Button
|
||||||
bind:layout
|
bind:layout
|
||||||
@@ -13,14 +12,15 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
import { layout } from './Store_chat';
|
||||||
|
|
||||||
export let my_class = "";
|
export let my_class = "";
|
||||||
export let my_title = "";
|
export let my_title = "";
|
||||||
export let layout = "";
|
|
||||||
export let new_layout = "";
|
export let new_layout = "";
|
||||||
export let on_click = "";
|
export let on_click = "";
|
||||||
|
|
||||||
function update_layout() {
|
function update_layout() {
|
||||||
layout = new_layout;
|
layout.set(new_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for btn list
|
/* .list
|
||||||
*/
|
*/
|
||||||
.list:not(:hover) {
|
.list:not(:hover) {
|
||||||
background-color: rgb(240, 240, 240);
|
background-color: rgb(240, 240, 240);
|
||||||
@@ -77,14 +77,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for transparent btn
|
/* .transparent
|
||||||
*/
|
*/
|
||||||
.transparent:not(:hover) {
|
.transparent:not(:hover) {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for deactivated btn
|
/* .deactivated
|
||||||
*/
|
*/
|
||||||
.deactivate {
|
.deactivate {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -92,7 +92,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for icon
|
/* .border
|
||||||
|
*/
|
||||||
|
.border {
|
||||||
|
border: 1px solid rgb(150, 150, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* .light
|
||||||
|
*/
|
||||||
|
.light {
|
||||||
|
background-color: rgb(233, 233, 233);
|
||||||
|
}
|
||||||
|
.light.border {
|
||||||
|
border: 1px solid rgb(204, 204, 204);
|
||||||
|
}
|
||||||
|
.light:hover {
|
||||||
|
background-color: rgb(220, 220, 220);
|
||||||
|
}
|
||||||
|
.light.border:hover {
|
||||||
|
border-color: rgb(200, 200, 200);
|
||||||
|
}
|
||||||
|
.light:active {
|
||||||
|
background-color: rgb(210, 210, 210);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* .thin
|
||||||
|
*/
|
||||||
|
.thin p {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* .icon
|
||||||
*/
|
*/
|
||||||
.icon p {
|
.icon p {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -107,7 +140,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for 3 dots btn
|
/* .dots
|
||||||
*/
|
*/
|
||||||
.dots::after {
|
.dots::after {
|
||||||
content: '\2807';
|
content: '\2807';
|
||||||
@@ -123,7 +156,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for close btn
|
/* .close
|
||||||
*/
|
*/
|
||||||
.close::before {
|
.close::before {
|
||||||
content: "";
|
content: "";
|
||||||
@@ -136,7 +169,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for back btn
|
/* .back
|
||||||
*/
|
*/
|
||||||
.back::before {
|
.back::before {
|
||||||
content: "";
|
content: "";
|
||||||
@@ -151,7 +184,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* for blocked user
|
/* .blocked
|
||||||
https://www.fileformat.info/info/unicode/category/So/list.htm
|
https://www.fileformat.info/info/unicode/category/So/list.htm
|
||||||
U+1F512 LOCK 🔒
|
U+1F512 LOCK 🔒
|
||||||
U+1F513 OPEN LOCK 🔓
|
U+1F513 OPEN LOCK 🔓
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
export let content = "warning";
|
||||||
|
export let bg_color = "rgb(201, 87, 34)";
|
||||||
|
export let color = "rgb(240, 240, 240)";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p style="background-color: {bg_color}; color: {color};">
|
||||||
|
{content}
|
||||||
|
</p>
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
<script>
|
import { layout } from './Store_chat';
|
||||||
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
export let back = "";
|
||||||
export let layout;
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
<Button bind:layout new_layout="home" my_class="chat">
|
<Button new_layout={back} my_class="chat">
|
||||||
chat
|
chat
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,16 +1,41 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
<script>
|
import { msgs, layout } from './Store_chat';
|
||||||
|
import { change_room, create_room } from './Request_rooms';
|
||||||
|
import Button from './Element_button.svelte';
|
||||||
|
import Warning from './Element_warning.svelte';
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
|
||||||
export let layout = "";
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
|
let room_name: string;
|
||||||
|
let room_type: string;
|
||||||
|
let room_password: string;
|
||||||
|
let response = {
|
||||||
|
status: 0,
|
||||||
|
message: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit(evt)
|
||||||
|
{
|
||||||
|
let formIsValid = evt.target.checkValidity();
|
||||||
|
|
||||||
|
if (!formIsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// send the new room
|
||||||
|
response = await create_room(room_name, room_type);
|
||||||
|
|
||||||
|
// go to room
|
||||||
|
if (response.status === 200)
|
||||||
|
await change_room(room_name);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,37 +45,45 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- panel_create -->
|
<!-- panel_create -->
|
||||||
<div class="panel panel_create">
|
<div class="panel panel_create __border_top">
|
||||||
<form>
|
<form on:submit|preventDefault={handleSubmit}>
|
||||||
|
{#if response.status >= 300}
|
||||||
|
<Warning content={response.message}/>
|
||||||
|
{/if}
|
||||||
<!-- name: -->
|
<!-- name: -->
|
||||||
<label for="chat_name"><p>new room name :</p></label>
|
<label for="chat_name"><p>new room name :</p></label>
|
||||||
<input id="chat_name" required>
|
<input id="chat_name" bind:value={room_name} name="room_name" required>
|
||||||
<!-- [ ] pubic -->
|
<!-- [ ] pubic -->
|
||||||
<input id="chat_public" type="radio" name="chat_create_type" checked>
|
<label for="chat_public" class="_radio">
|
||||||
<label for="chat_public" class="_radio"><p>public</p></label>
|
<p>public</p>
|
||||||
|
<input id="chat_public" bind:group={room_type} type="radio" name="room_type" value="public" required>
|
||||||
|
</label>
|
||||||
<!-- [ ] private -->
|
<!-- [ ] private -->
|
||||||
<input id="chat_private" type="radio" name="chat_create_type">
|
<label for="chat_private" class="_radio hide">
|
||||||
<label for="chat_private" class="_radio"><p>private</p></label>
|
<p>private</p>
|
||||||
|
<input id="chat_private" bind:group={room_type} type="radio" name="room_type" value="private" required>
|
||||||
|
</label>
|
||||||
<!-- [ ] protected -->
|
<!-- [ ] protected -->
|
||||||
<input id="chat_protected" class="__check_change_next" type="radio" name="chat_create_type">
|
<label for="chat_protected" class="_radio hide">
|
||||||
<label for="chat_protected" class="_radio"><p>protected</p></label>
|
<p>protected</p>
|
||||||
|
<input id="chat_protected" bind:group={room_type} type="radio" name="room_type" value="protected" required>
|
||||||
|
</label>
|
||||||
<!-- [x] protected -->
|
<!-- [x] protected -->
|
||||||
<div class="__to_show">
|
{#if room_type === 'protected'}
|
||||||
|
<div>
|
||||||
<label for="chat_pswd"><p>choose a password :</p></label>
|
<label for="chat_pswd"><p>choose a password :</p></label>
|
||||||
<input id="chat_pswd" type="password" placeholder="minimum 8 characters" minlength="8">
|
<input id="chat_pswd" bind:value={room_password} type="password" placeholder="minimum 8 characters" minlength="8" name="password" required>
|
||||||
<p>confirm password :</p>
|
|
||||||
<input type="password">
|
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<input type="submit" value="⮡">
|
<input type="submit" value="⮡">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -68,42 +101,32 @@
|
|||||||
/ auto 1fr auto ;
|
/ auto 1fr auto ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* temp
|
||||||
|
*/
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* radio elements style check
|
/* radio elements style check
|
||||||
*/
|
*/
|
||||||
form input[type=radio] {
|
.panel label._radio {
|
||||||
display: none;
|
display: inline;
|
||||||
}
|
margin: 10px 0px 0px auto;
|
||||||
form label._radio {
|
|
||||||
margin: 0px 20px 0px auto;
|
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
form label._radio p {
|
.panel label._radio * {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.panel label._radio p {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
form label._radio::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: calc(50% - 6px);
|
|
||||||
right: 0px;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 2px solid rgb(150, 150, 150);
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
form input[type=radio]:checked
|
|
||||||
+ label._radio::after {
|
|
||||||
background-color: rgb(200, 200, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* submit
|
/* submit
|
||||||
*/
|
*/
|
||||||
form input[type=submit] {
|
.panel input[type=submit] {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,36 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout, msgs, user } from './Store_chat';
|
||||||
export let layout;
|
import { change_room, get_room_messages, get_all_rooms } from './Request_rooms';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
|
let rooms = get_all_rooms();
|
||||||
|
|
||||||
|
// go to clicked room
|
||||||
|
async function go_to_room(evt)
|
||||||
|
{
|
||||||
|
console.log("inside go_to_room");
|
||||||
|
await change_room(evt.target.innerText);
|
||||||
|
await get_room_messages();
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- settings -->
|
<!-- settings -->
|
||||||
<Button bind:layout new_layout="settings" my_class="settings dots icon">
|
<Button new_layout="settings" my_class="settings dots icon">
|
||||||
settings
|
settings
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- new -->
|
<!-- new -->
|
||||||
<Button bind:layout new_layout="new" my_class="new transparent">
|
<Button new_layout="new" my_class="new transparent">
|
||||||
new
|
new
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -30,18 +41,16 @@
|
|||||||
<div class="__show_if_only_child">
|
<div class="__show_if_only_child">
|
||||||
<p class="__center">/ you have no chat room yet /</p>
|
<p class="__center">/ you have no chat room yet /</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- placeholders
|
{#await rooms}
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
<!-- promise is pending -->
|
||||||
a room
|
<p>rooms are loaded...</p>
|
||||||
|
{:then rooms}
|
||||||
|
{#each rooms as room}
|
||||||
|
<Button my_class="list" on_click={go_to_room}>
|
||||||
|
{room.name}
|
||||||
</Button>
|
</Button>
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
{/each}
|
||||||
another room
|
{/await}
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
placeholder
|
|
||||||
</Button>
|
|
||||||
------------- -->
|
|
||||||
<!-- END placeholders -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout } from './Store_chat';
|
||||||
export let layout = "";
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,40 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout, msgs, user, socket } from './Store_chat';
|
||||||
export let layout = "";
|
import { join_room, change_room, get_room_messages } from './Request_rooms';
|
||||||
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
|
let rooms = [];
|
||||||
|
|
||||||
|
// ask api for the rooms
|
||||||
|
const get_rooms = fetch('/api/v2/chat/allrooms')
|
||||||
|
.then(resp => resp.json())
|
||||||
|
.then(data =>
|
||||||
|
{
|
||||||
|
console.log("data.rooms:", data.rooms);
|
||||||
|
for (let room of data.rooms)
|
||||||
|
console.log(room.name);
|
||||||
|
rooms = data.rooms;
|
||||||
|
});
|
||||||
|
|
||||||
|
// join the room
|
||||||
|
async function join_rooms(evt)
|
||||||
|
{
|
||||||
|
console.log("inside join_room");
|
||||||
|
let room_name = evt.target.innerText;
|
||||||
|
|
||||||
|
await join_room(room_name);
|
||||||
|
await change_room(room_name);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,13 +44,13 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- panel_new -->
|
<!-- panel_new -->
|
||||||
<div class="panel panel_new __border_top">
|
<div class="panel panel_new __border_top">
|
||||||
<Button bind:layout new_layout="create" my_class="create">
|
<Button new_layout="create" my_class="create">
|
||||||
create
|
create
|
||||||
</Button>
|
</Button>
|
||||||
<p>join room :</p>
|
<p>join room :</p>
|
||||||
@@ -34,36 +58,16 @@
|
|||||||
<div class="__show_if_only_child">
|
<div class="__show_if_only_child">
|
||||||
<p class="__center">/ there are no public rooms yet /</p>
|
<p class="__center">/ there are no public rooms yet /</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- placeholders
|
{#await get_rooms}
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
<!-- promise is pending -->
|
||||||
placeholder
|
<p>rooms are loaded...</p>
|
||||||
|
{:then}
|
||||||
|
{#each rooms as room}
|
||||||
|
<Button my_class="list" on_click={join_rooms}>
|
||||||
|
{room.name}
|
||||||
</Button>
|
</Button>
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
{/each}
|
||||||
join room
|
{/await}
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
one room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
another room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
one room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
another room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
one room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
another room
|
|
||||||
</Button>
|
|
||||||
<Button bind:layout new_layout="room" my_class="list">
|
|
||||||
one more room
|
|
||||||
</Button>
|
|
||||||
------------- -->
|
|
||||||
<!-- END placeholders -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout } from './Store_chat';
|
||||||
export let layout = "";
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,28 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout, socket, msgs, add_msg, room_name } from './Store_chat';
|
||||||
import Msg from './Chat_msg.svelte';
|
import Button from './Element_button.svelte';
|
||||||
import io from 'socket.io-client';
|
import Msg from './Element_msg.svelte';
|
||||||
|
|
||||||
export let layout = "";
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
let msg = "";
|
let msg = "";
|
||||||
let text_area;
|
let text_area;
|
||||||
let msgs = [];
|
|
||||||
|
|
||||||
function add_msg(from, the_msg)
|
|
||||||
{
|
|
||||||
msgs = [...msgs, { content: the_msg, name: from }];
|
|
||||||
}
|
|
||||||
|
|
||||||
function send_msg()
|
function send_msg()
|
||||||
{
|
{
|
||||||
msg = msg.trim();
|
msg = msg.trim();
|
||||||
|
|
||||||
if (msg.length > 0) {
|
if (msg.length > 0) {
|
||||||
//socket.emit('sendmsg', msg);
|
socket.emit('message', msg);
|
||||||
add_msg("me", msg);
|
add_msg("me", msg);
|
||||||
|
console.log(msgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = "";
|
msg = "";
|
||||||
text_area.focus();
|
text_area.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function send_msg_if(evt)
|
function enter_send_msg(evt)
|
||||||
{
|
{
|
||||||
if (evt.shiftKey && evt.key === "Enter")
|
if (evt.shiftKey && evt.key === "Enter")
|
||||||
{
|
{
|
||||||
@@ -44,25 +36,25 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- room_name -->
|
<!-- room_name -->
|
||||||
<Button bind:layout new_layout="room_set" my_class="room_name transparent">
|
<Button new_layout="room_set" my_class="room_name transparent">
|
||||||
<room_name>
|
{$room_name}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- msg -->
|
<!-- msg -->
|
||||||
<div class="panel panel_msg">
|
<div class="panel panel_msg">
|
||||||
<div class="msg_thread">
|
<div class="msg_thread">
|
||||||
{#each msgs as msg}
|
{#each $msgs as msg}
|
||||||
<Msg name={msg.name}>{@html msg.content}</Msg>
|
<Msg name={msg.name}>{@html msg.message}</Msg>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -73,7 +65,7 @@
|
|||||||
class="text_area"
|
class="text_area"
|
||||||
bind:innerHTML={msg}
|
bind:innerHTML={msg}
|
||||||
bind:this={text_area}
|
bind:this={text_area}
|
||||||
on:keypress={send_msg_if}
|
on:keypress={enter_send_msg}
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout } from './Store_chat';
|
||||||
export let layout = "";
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- panel_room_set -->
|
<!-- panel_room_set -->
|
||||||
<div class="panel panel_room_set __border_top">
|
<div class="panel panel_room_set __border_top">
|
||||||
<Button bind:layout new_layout="create" my_class="create">
|
<Button new_layout="create" my_class="create">
|
||||||
leave
|
leave
|
||||||
</Button>
|
</Button>
|
||||||
<p>room users :</p>
|
<p>room users :</p>
|
||||||
@@ -36,16 +36,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- placeholders
|
<!-- placeholders
|
||||||
------------- -->
|
------------- -->
|
||||||
<Button bind:layout new_layout="user" my_class="list">
|
<Button new_layout="user" my_class="list">
|
||||||
user 1
|
user 1
|
||||||
</Button>
|
</Button>
|
||||||
<Button bind:layout new_layout="user" my_class="list blocked">
|
<Button new_layout="user" my_class="list blocked">
|
||||||
user 2
|
user 2
|
||||||
</Button>
|
</Button>
|
||||||
<Button bind:layout new_layout="user" my_class="list">
|
<Button new_layout="user" my_class="list">
|
||||||
user 3
|
user 3
|
||||||
</Button>
|
</Button>
|
||||||
<Button bind:layout new_layout="user" my_class="list">
|
<Button new_layout="user" my_class="list">
|
||||||
user 4
|
user 4
|
||||||
</Button>
|
</Button>
|
||||||
<!-- END placeholders -->
|
<!-- END placeholders -->
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout } from './Store_chat';
|
||||||
export let layout = "";
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Button from './Chat_button.svelte';
|
import { layout } from './Store_chat';
|
||||||
export let layout = "";
|
import Button from './Element_button.svelte';
|
||||||
|
|
||||||
export let back = "";
|
export let back = "";
|
||||||
|
|
||||||
let mute = "mute";
|
let mute = "mute";
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="grid_box">
|
<div class="grid_box">
|
||||||
|
|
||||||
<!-- back -->
|
<!-- back -->
|
||||||
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
|
<Button new_layout={back} my_class="back icon" my_title="go back {back}">
|
||||||
back
|
back
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<Button bind:layout new_layout="close" my_class="close icon">
|
<Button new_layout="close" my_class="close icon">
|
||||||
close
|
close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { msgs, user, layout, socket, room_name } from './Store_chat';
|
||||||
|
|
||||||
|
export async function get_room_messages()
|
||||||
|
{
|
||||||
|
console.log("in get_room_messages");
|
||||||
|
const response = await fetch('/api/v2/chat/messages');
|
||||||
|
const data = await response.json();
|
||||||
|
const messages = data.messages;
|
||||||
|
|
||||||
|
messages.forEach(function(item) {
|
||||||
|
if (item.name === user.username) {
|
||||||
|
item.name = "me";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
msgs.set(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function create_room(room_name, room_type)
|
||||||
|
{
|
||||||
|
console.log("in create_room");
|
||||||
|
|
||||||
|
let form_data = {
|
||||||
|
room_name: room_name,
|
||||||
|
room_type: room_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
// send the new room
|
||||||
|
const response = await fetch('/api/v2/chat/create', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(form_data),
|
||||||
|
});
|
||||||
|
|
||||||
|
// get response status and message
|
||||||
|
let response_status = response.status;
|
||||||
|
let data = await response.json();
|
||||||
|
let response_message = "";
|
||||||
|
if (data.message)
|
||||||
|
response_message = data.message;
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response_status,
|
||||||
|
message: response_message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function join_room(room_name)
|
||||||
|
{
|
||||||
|
console.log("in join_room");
|
||||||
|
|
||||||
|
let name = {
|
||||||
|
room_name: room_name,
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/v2/chat/join', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(name),
|
||||||
|
});
|
||||||
|
let data = await response.json();
|
||||||
|
console.log(data.message);
|
||||||
|
|
||||||
|
socket.emit('join', room_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function change_room(name)
|
||||||
|
{
|
||||||
|
console.log("in change_room");
|
||||||
|
|
||||||
|
let r_name = {
|
||||||
|
room_name: name,
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/v2/chat/change', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(r_name),
|
||||||
|
});
|
||||||
|
let data = await response.json();
|
||||||
|
console.log(data.message);
|
||||||
|
|
||||||
|
await get_room_messages();
|
||||||
|
socket.emit('join', name);
|
||||||
|
|
||||||
|
room_name.set(name);
|
||||||
|
layout.set("room");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_all_rooms()
|
||||||
|
{
|
||||||
|
console.log("in get_all_rooms");
|
||||||
|
|
||||||
|
// ask api for the rooms
|
||||||
|
const response = await fetch('/api/v2/chat/myrooms');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
console.log("data.rooms:", data.rooms);
|
||||||
|
for (let room of data.rooms)
|
||||||
|
console.log(room.name);
|
||||||
|
let rooms = data.rooms;
|
||||||
|
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { user, msgs } from './Store_chat';
|
||||||
|
|
||||||
|
export function socket_events(socket)
|
||||||
|
{
|
||||||
|
socket.on('message', function(from, message)
|
||||||
|
{
|
||||||
|
console.log("received msg:", message, from);
|
||||||
|
if (from === user.username)
|
||||||
|
from = "me";
|
||||||
|
msgs.update(msgs => [...msgs, { name: from, message: message }]);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import io from 'socket.io-client';
|
||||||
|
import { set_socket, set_user } from './Store_chat';
|
||||||
|
import { socket_events } from './Socket_events';
|
||||||
|
|
||||||
|
const address = `http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}`;
|
||||||
|
|
||||||
|
export async function init_socket()
|
||||||
|
{
|
||||||
|
const response = await fetch(`${address}/api/v2/user`);
|
||||||
|
const response_data = await response.json();
|
||||||
|
|
||||||
|
set_user(response_data);
|
||||||
|
|
||||||
|
let socket = await io(address,
|
||||||
|
{
|
||||||
|
path: '/chat',
|
||||||
|
query:
|
||||||
|
{
|
||||||
|
username: response_data.username,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
set_socket(socket);
|
||||||
|
|
||||||
|
socket.on('connect', function(){ console.log("socket.io connected"); });
|
||||||
|
socket.on('disconnect', function(){ console.log("socket.io disconnected"); });
|
||||||
|
socket.on('connect_error', function(){ console.log("socket.io connect_error"); });
|
||||||
|
socket.on('connect_timeout', function(){ console.log("socket.io connect_timeout"); });
|
||||||
|
socket.on('error', function(){ console.log("socket.io error"); });
|
||||||
|
socket.on('reconnect', function(){ console.log("socket.io reconnect"); });
|
||||||
|
socket.on('reconnect_attempt', function(){ console.log("socket.io reconnect_attempt"); });
|
||||||
|
socket.on('reconnecting', function(){ console.log("socket.io reconnecting"); });
|
||||||
|
socket.on('reconnect_error', function(){ console.log("socket.io reconnect_error"); });
|
||||||
|
socket.on('reconnect_failed', function(){ console.log("socket.io reconnect_failed"); });
|
||||||
|
socket.on('ping', function(){ console.log("socket.io ping"); });
|
||||||
|
socket.on('pong', function(){ console.log("socket.io pong"); });
|
||||||
|
|
||||||
|
socket_events(socket);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export let msgs = writable([]);
|
||||||
|
export let layout = writable("close");
|
||||||
|
export let room_name = writable("");
|
||||||
|
|
||||||
|
export let user;
|
||||||
|
export let socket;
|
||||||
|
|
||||||
|
export function set_user(new_user) { user = new_user; }
|
||||||
|
export function set_socket(new_socket) { socket = new_socket; }
|
||||||
|
|
||||||
|
export function add_msg(name: string, message: string)
|
||||||
|
{
|
||||||
|
msgs.update(msgs => [...msgs, { name: "me", message: message }]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
export let layout = "";
|
||||||
|
export let layouts = [];
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div style="display: flex; flex-direction: column; font-size: 12px; position: fixed; top: 20px; left: 20px; background-color: white;">
|
||||||
|
<p>temp, for testing :</p>
|
||||||
|
<button on:click={function(){layout = "close" }}>close</button>
|
||||||
|
<button on:click={function(){layout = "home" }}>home</button>
|
||||||
|
<button on:click={function(){layout = "room" }}>room</button>
|
||||||
|
<button on:click={function(){layout = "new" }}>new</button>
|
||||||
|
<button on:click={function(){layout = "settings" }}>settings</button>
|
||||||
|
<button on:click={function(){layout = "room_set" }}>room_set</button>
|
||||||
|
<button on:click={function(){layout = "protected"}}>protected</button>
|
||||||
|
<button on:click={function(){layout = "create" }}>create</button>
|
||||||
|
<button on:click={function(){layout = "mute" }}>mute</button>
|
||||||
|
<button on:click={function(){
|
||||||
|
layouts = ["settings", "settings"];
|
||||||
|
layout = "user";
|
||||||
|
}}>user from settings</button>
|
||||||
|
<button on:click={function(){
|
||||||
|
layouts = ["room_set", "room_set"];
|
||||||
|
layout = "user";
|
||||||
|
}}>user from room_set</button>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user