feat(tour): added tournament broadcast
This commit is contained in:
parent
eccc763644
commit
8e6ff3aedc
10 changed files with 157 additions and 41 deletions
|
|
@ -39,7 +39,7 @@
|
||||||
<div id="game-modal" class="gamePopup hidden">
|
<div id="game-modal" class="gamePopup hidden">
|
||||||
<div class="popUpMessage">
|
<div class="popUpMessage">
|
||||||
<div id="game-info">
|
<div id="game-info">
|
||||||
<p class="modal-messages" id="modal-message"></p>
|
<p class="" id="modal-message"></p>
|
||||||
<button id="close-modal-message" class="btn-style relative bottom-8 left-85">Close</button>
|
<button id="close-modal-message" class="btn-style relative bottom-8 left-85">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,11 @@ function initChatSocket() {
|
||||||
openMessagePopup(message);
|
openMessagePopup(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//receives broadcast of the next GAME
|
||||||
|
socket.on("tourStatus", (message: string) => {
|
||||||
|
openMessagePopup(message);
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("listBud", async (myBuddies: string[]) => {
|
socket.on("listBud", async (myBuddies: string[]) => {
|
||||||
const buddies = document.getElementById(
|
const buddies = document.getElementById(
|
||||||
"div-buddies",
|
"div-buddies",
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,14 @@ import { incrementCounter } from "./incrementCounter";
|
||||||
// return count;
|
// return count;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export async function openMessagePopup(message: any) {
|
export async function openMessagePopup(message: string) {
|
||||||
|
|
||||||
const modalmessage = document.getElementById("modal-message") ?? null;
|
const modalmessage = document.getElementById("modal-message") ?? null;
|
||||||
if(!message) return
|
if(!message) return
|
||||||
const obj = message;
|
const obj = message;
|
||||||
if (modalmessage) {
|
if (modalmessage) {
|
||||||
const messageElement = document.createElement("div");
|
const messageElement = document.createElement("div");
|
||||||
messageElement.innerHTML = `
|
messageElement.innerHTML = `<div id="profile-about">${message}</div>`;
|
||||||
<div id="profile-about">Game-Info: ${incrementCounter()}: ${obj.nextGame}</div>
|
|
||||||
`;
|
|
||||||
modalmessage.appendChild(messageElement);
|
modalmessage.appendChild(messageElement);
|
||||||
modalmessage.scrollTop = modalmessage.scrollHeight;
|
modalmessage.scrollTop = modalmessage.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ declare module 'fastify' {
|
||||||
blockBtn: (data: blockedUnBlocked) => void;
|
blockBtn: (data: blockedUnBlocked) => void;
|
||||||
isBlockdBtn: (data: blockedUnBlocked) => void;
|
isBlockdBtn: (data: blockedUnBlocked) => void;
|
||||||
check_Block_button: (data: blockedUnBlocked) => void;
|
check_Block_button: (data: blockedUnBlocked) => void;
|
||||||
|
tourStatus: (data: string) => void;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,13 @@ import { clientChat } from './app';
|
||||||
* @param fastify
|
* @param fastify
|
||||||
* @param gameLink
|
* @param gameLink
|
||||||
*/
|
*/
|
||||||
export async function broadcastNextGame(fastify: FastifyInstance, gameLink?: Promise<string>) {
|
export async function broadcastNextGame(fastify: FastifyInstance, gameLink: string) {
|
||||||
const link = gameLink ? await gameLink : undefined;
|
|
||||||
const sockets = await fastify.io.fetchSockets();
|
const sockets = await fastify.io.fetchSockets();
|
||||||
for (const socket of sockets) {
|
for (const socket of sockets) {
|
||||||
const clientInfo = clientChat.get(socket.id);
|
const clientInfo = clientChat.get(socket.id);
|
||||||
if (!clientInfo?.user) {
|
if (!clientInfo?.user) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (link) {
|
socket.emit('nextGame', gameLink);
|
||||||
socket.emit('nextGame', link);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
21
src/chat/src/broadcastTourStatus.ts
Normal file
21
src/chat/src/broadcastTourStatus.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { FastifyInstance } from 'fastify';
|
||||||
|
import { clientChat } from './app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function broadcast a clickable link
|
||||||
|
* @param fastify
|
||||||
|
* @param gameLink
|
||||||
|
*/
|
||||||
|
export async function broadcastTourStatus(fastify: FastifyInstance, gameLink?: string) {
|
||||||
|
const link = gameLink;
|
||||||
|
const sockets = await fastify.io.fetchSockets();
|
||||||
|
for (const socket of sockets) {
|
||||||
|
const clientInfo = clientChat.get(socket.id);
|
||||||
|
if (!clientInfo?.user) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (link) {
|
||||||
|
socket.emit('tourStatus', link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -3,7 +3,7 @@ import { Static, Type } from 'typebox';
|
||||||
import { broadcastNextGame } from '../broadcastNextGame';
|
import { broadcastNextGame } from '../broadcastNextGame';
|
||||||
|
|
||||||
export const ChatReq = Type.Object({
|
export const ChatReq = Type.Object({
|
||||||
message: Type.String(),
|
nextGame: Type.String(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ChatReq = Static<typeof ChatReq>;
|
export type ChatReq = Static<typeof ChatReq>;
|
||||||
|
|
@ -27,21 +27,14 @@ export type ChatReq = Static<typeof ChatReq>;
|
||||||
// export default route;
|
// export default route;
|
||||||
|
|
||||||
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
|
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
fastify.post('/api/chat/broadcast', {
|
fastify.post<{ Body: ChatReq }>('/broadcastNextGame', {
|
||||||
schema: {
|
schema: {
|
||||||
body: {
|
body: ChatReq,
|
||||||
type: 'object',
|
hide: true,
|
||||||
required: ['nextGame'],
|
|
||||||
properties: {
|
|
||||||
nextGame: { type: 'string' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, async (req, reply) => {
|
}, async function(req, reply) {
|
||||||
const gameLink: Promise<string> = Promise.resolve(req.body as string);
|
this.log.info({ msg: 'Broadcasting nextGame status', ...req.body });
|
||||||
if (gameLink) {
|
broadcastNextGame(fastify, req.body.nextGame);
|
||||||
broadcastNextGame(fastify, gameLink);
|
|
||||||
}
|
|
||||||
return reply.send({ status: 'ok' });
|
return reply.send({ status: 'ok' });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
44
src/chat/src/routes/broadcastTourStatus.ts
Normal file
44
src/chat/src/routes/broadcastTourStatus.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
|
import { Static, Type } from 'typebox';
|
||||||
|
import { broadcastTourStatus } from '../broadcastTourStatus';
|
||||||
|
|
||||||
|
export const ChatReq = Type.Object({
|
||||||
|
message: Type.String(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ChatReq = Static<typeof ChatReq>;
|
||||||
|
|
||||||
|
// const route: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
|
// fastify.post<{ Body: ChatReq }>(
|
||||||
|
// '/api/chat/broadcast',
|
||||||
|
// {
|
||||||
|
// schema: {
|
||||||
|
// body: ChatReq,
|
||||||
|
// hide: true,
|
||||||
|
// },
|
||||||
|
// config: { requireAuth: false },
|
||||||
|
// },
|
||||||
|
// async function(req, res) {
|
||||||
|
// // broadcast(this, { command: '', destination: '', user: 'CMwaLeSever!!', text: req.body.message, SenderWindowID: 'server' });
|
||||||
|
// void res;
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
// export default route;
|
||||||
|
|
||||||
|
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
|
fastify.post<{ Body: ChatReq }>('/broadcastTourStatus', {
|
||||||
|
schema: {
|
||||||
|
body: ChatReq,
|
||||||
|
hide: true,
|
||||||
|
},
|
||||||
|
}, async function(req, reply) {
|
||||||
|
const gameLink: string = req.body.message;
|
||||||
|
if (gameLink) {
|
||||||
|
broadcastTourStatus(fastify, gameLink);
|
||||||
|
}
|
||||||
|
return reply.send({ status: 'ok' });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export default route;
|
||||||
|
|
||||||
|
|
@ -90,8 +90,12 @@ class StateI {
|
||||||
g.rdy_timer = Date.now();
|
g.rdy_timer = Date.now();
|
||||||
this.games.set(gameId, g);
|
this.games.set(gameId, g);
|
||||||
|
|
||||||
if (u1) { u1.currentGame = gameId; }
|
if (u1) {
|
||||||
if (u2) { u2.currentGame = gameId; }
|
u1.currentGame = gameId;
|
||||||
|
}
|
||||||
|
if (u2) {
|
||||||
|
u2.currentGame = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
g.gameUpdate = setInterval(() => {
|
g.gameUpdate = setInterval(() => {
|
||||||
g.tick();
|
g.tick();
|
||||||
|
|
@ -193,6 +197,26 @@ class StateI {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async broadcastTourStatus(message: string) {
|
||||||
|
try {
|
||||||
|
const resp = await fetch('http://app-chat/broadcastTourStatus', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ message }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resp.ok) {
|
||||||
|
throw resp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.fastify.log.info('tour-status info to chat success');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e: unknown) {
|
||||||
|
this.fastify.log.error(`tour-status info to chat failed: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private createTournament(sock: SSocket) {
|
private createTournament(sock: SSocket) {
|
||||||
const user = this.users.get(sock.authUser.id);
|
const user = this.users.get(sock.authUser.id);
|
||||||
if (isNullish(user)) return;
|
if (isNullish(user)) return;
|
||||||
|
|
@ -215,7 +239,14 @@ class StateI {
|
||||||
|
|
||||||
private cleanupTournament() {
|
private cleanupTournament() {
|
||||||
if (this.tournament === null) return;
|
if (this.tournament === null) return;
|
||||||
if (this.tournament.state === 'ended') { this.fastify.db.createNewTournamentById(this.tournament.owner, this.tournament.users.values().toArray(), this.tournament.games); }
|
if (this.tournament.state === 'ended') {
|
||||||
|
this.fastify.db.createNewTournamentById(
|
||||||
|
this.tournament.owner,
|
||||||
|
this.tournament.users.values().toArray(),
|
||||||
|
this.tournament.games,
|
||||||
|
);
|
||||||
|
this.broadcastTourStatus('The tournament has ended');
|
||||||
|
}
|
||||||
this.tournament = null;
|
this.tournament = null;
|
||||||
this.fastify.log.info('Tournament has been ended');
|
this.fastify.log.info('Tournament has been ended');
|
||||||
}
|
}
|
||||||
|
|
@ -231,8 +262,15 @@ class StateI {
|
||||||
}
|
}
|
||||||
|
|
||||||
public newPausedGame(suid1: string, suid2: string): GameId | undefined {
|
public newPausedGame(suid1: string, suid2: string): GameId | undefined {
|
||||||
this.fastify.log.info('new game request: suid1: ' + suid1 + '\tsuid2: ' + suid2);
|
this.fastify.log.info(
|
||||||
if (!this.fastify.db.getUser(suid1) || !this.fastify.db.getUser(suid2)) { return undefined; }
|
'new game request: suid1: ' + suid1 + '\tsuid2: ' + suid2,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!this.fastify.db.getUser(suid1) ||
|
||||||
|
!this.fastify.db.getUser(suid2)
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
this.fastify.log.info('new paused start');
|
this.fastify.log.info('new paused start');
|
||||||
const uid1: UserId = suid1 as UserId;
|
const uid1: UserId = suid1 as UserId;
|
||||||
const uid2: UserId = suid2 as UserId;
|
const uid2: UserId = suid2 as UserId;
|
||||||
|
|
@ -313,7 +351,9 @@ class StateI {
|
||||||
const user = this.users.get(sock.authUser.id);
|
const user = this.users.get(sock.authUser.id);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
if (this.tournament && this.tournament.users.has(sock.authUser.id)) return;
|
if (this.tournament && this.tournament.users.has(sock.authUser.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const gameId = newUUID() as unknown as GameId;
|
const gameId = newUUID() as unknown as GameId;
|
||||||
const g = Pong.makeLocal(user.id);
|
const g = Pong.makeLocal(user.id);
|
||||||
|
|
@ -388,19 +428,28 @@ class StateI {
|
||||||
|
|
||||||
if (this.games.has(game_id) === false) {
|
if (this.games.has(game_id) === false) {
|
||||||
this.fastify.log.warn('gameId:' + g_id + ' is unknown!');
|
this.fastify.log.warn('gameId:' + g_id + ' is unknown!');
|
||||||
return (JoinRes.no);
|
return JoinRes.no;
|
||||||
}
|
}
|
||||||
const game: Pong = this.games.get(game_id)!;
|
const game: Pong = this.games.get(game_id)!;
|
||||||
if (game.local === true || (game.userLeft !== sock.authUser.id && game.userRight !== sock.authUser.id)) {
|
if (
|
||||||
this.fastify.log.warn('user trying to connect to a game he\'s not part of: gameId:' + g_id + ' userId:' + sock.authUser.id);
|
game.local === true ||
|
||||||
return (JoinRes.no);
|
(game.userLeft !== sock.authUser.id &&
|
||||||
|
game.userRight !== sock.authUser.id)
|
||||||
|
) {
|
||||||
|
this.fastify.log.warn(
|
||||||
|
'user trying to connect to a game he\'s not part of: gameId:' +
|
||||||
|
g_id +
|
||||||
|
' userId:' +
|
||||||
|
sock.authUser.id,
|
||||||
|
);
|
||||||
|
return JoinRes.no;
|
||||||
}
|
}
|
||||||
game.userOnPage[game.userLeft === sock.authUser.id ? 0 : 1] = true;
|
game.userOnPage[game.userLeft === sock.authUser.id ? 0 : 1] = true;
|
||||||
if (game.userOnPage[0] === game.userOnPage[1]) {
|
if (game.userOnPage[0] === game.userOnPage[1]) {
|
||||||
this.fastify.log.info('Paused game start: gameId:' + g_id);
|
this.fastify.log.info('Paused game start: gameId:' + g_id);
|
||||||
this.initGame(game, game_id, game.userLeft, game.userRight);
|
this.initGame(game, game_id, game.userLeft, game.userRight);
|
||||||
}
|
}
|
||||||
return (JoinRes.yes);
|
return JoinRes.yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerUser(socket: SSocket): void {
|
public registerUser(socket: SSocket): void {
|
||||||
|
|
@ -433,7 +482,9 @@ class StateI {
|
||||||
|
|
||||||
socket.on('gameMove', (e) => this.gameMove(socket, e));
|
socket.on('gameMove', (e) => this.gameMove(socket, e));
|
||||||
socket.on('localGame', () => this.newLocalGame(socket));
|
socket.on('localGame', () => this.newLocalGame(socket));
|
||||||
socket.on('joinGame', (g_id, ack) => { return (ack(this.tryJoinGame(g_id, socket))); });
|
socket.on('joinGame', (g_id, ack) => {
|
||||||
|
return ack(this.tryJoinGame(g_id, socket));
|
||||||
|
});
|
||||||
// todo: allow passing nickname
|
// todo: allow passing nickname
|
||||||
socket.on('tourRegister', () =>
|
socket.on('tourRegister', () =>
|
||||||
this.registerForTournament(socket, null),
|
this.registerForTournament(socket, null),
|
||||||
|
|
@ -522,7 +573,7 @@ class StateI {
|
||||||
if (!game.local) {
|
if (!game.local) {
|
||||||
const payload = { nextGame: chat_text };
|
const payload = { nextGame: chat_text };
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('http://app-chat/api/chat/broadcast', {
|
const resp = await fetch('http://app-chat/broadcastNextGame', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-type': 'application/json' },
|
headers: { 'Content-type': 'application/json' },
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
|
|
@ -548,7 +599,9 @@ class StateI {
|
||||||
|
|
||||||
if (this.users.get(socket.authUser.id)?.currentGame !== null) return;
|
if (this.users.get(socket.authUser.id)?.currentGame !== null) return;
|
||||||
|
|
||||||
if (this.tournament && this.tournament.users.has(socket.authUser.id)) return;
|
if (this.tournament && this.tournament.users.has(socket.authUser.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.queue.add(socket.authUser.id);
|
this.queue.add(socket.authUser.id);
|
||||||
socket.emit('queueEvent', 'registered');
|
socket.emit('queueEvent', 'registered');
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ export class Tournament {
|
||||||
public startTimeout: NodeJS.Timeout | undefined;
|
public startTimeout: NodeJS.Timeout | undefined;
|
||||||
public games: PongGameId[] = [];
|
public games: PongGameId[] = [];
|
||||||
|
|
||||||
constructor(public owner: UserId) { }
|
constructor(public owner: UserId) {
|
||||||
|
State.broadcastTourStatus('A new Tournament has been created');
|
||||||
|
}
|
||||||
|
|
||||||
public addUser(id: UserId, name: string) {
|
public addUser(id: UserId, name: string) {
|
||||||
if (this.state !== 'prestart') return;
|
if (this.state !== 'prestart') return;
|
||||||
|
|
@ -35,6 +37,7 @@ export class Tournament {
|
||||||
if (this.state !== 'prestart') return;
|
if (this.state !== 'prestart') return;
|
||||||
if (this.users.size < 2) {
|
if (this.users.size < 2) {
|
||||||
this.state = 'canceled';
|
this.state = 'canceled';
|
||||||
|
State.broadcastTourStatus('The tournament has been canceled !');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.state = 'playing';
|
this.state = 'playing';
|
||||||
|
|
@ -54,6 +57,7 @@ export class Tournament {
|
||||||
comb.forEach(([u1, u2]) => { result.push([u1, u2]); });
|
comb.forEach(([u1, u2]) => { result.push([u1, u2]); });
|
||||||
this.matchup = result;
|
this.matchup = result;
|
||||||
this.setupNextGame();
|
this.setupNextGame();
|
||||||
|
State.broadcastTourStatus('The tournament Started !');
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupNextGame() {
|
private setupNextGame() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue