From a64fadf103e939e9b9766f2c0dd9f87904599267 Mon Sep 17 00:00:00 2001 From: CHIBOUB Chakib Date: Tue, 10 Sep 2024 16:04:47 +0200 Subject: [PATCH 1/3] adrien code visible --- docker-compose.yml | 165 ++++++++++++++++++ docker-compose.yml_old | 75 ++++++++ .../templates/pong/tournament_brackets.html | 6 + pong/game/tournament.py | 36 ++-- pong/settings.py | 4 +- 5 files changed, 267 insertions(+), 19 deletions(-) create mode 100644 docker-compose.yml_old diff --git a/docker-compose.yml b/docker-compose.yml index aa21870..33a4a7e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,63 @@ services: + setup: + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + container_name: setup + user: "0" + volumes: + - certs:/usr/share/elasticsearch/config/certs + command: > + bash -c ' + if [ x${ELASTIC_PASSWORD} == x ]; then + echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; + exit 1; + elif [ x${KIBANA_PASSWORD} == x ]; then + echo "Set the KIBANA_PASSWORD environment variable in the .env file"; + exit 1; + fi; + if [ ! -f config/certs/ca.zip ]; then + echo "Creating CA"; + bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; + unzip config/certs/ca.zip -d config/certs; + fi; + if [ ! -f config/certs/certs.zip ]; then + echo "Creating certs"; + echo -ne \ + "instances:\n"\ + " - name: es01\n"\ + " dns:\n"\ + " - es01\n"\ + " - localhost\n"\ + " ip:\n"\ + " - 127.0.0.1\n"\ + " - name: kibana\n"\ + " dns:\n"\ + " - kibana\n"\ + " - localhost\n"\ + " ip:\n"\ + " - 127.0.0.1\n"\ + > config/certs/instances.yml; + + bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; + unzip config/certs/certs.zip -d config/certs; + fi; + + echo "Setting file permissions" + chown -R root:root config/certs; + find . -type d -exec chmod 750 \{\} \;; + find . -type f -exec chmod 640 \{\} \;; + + echo "Waiting for Elasticsearch availability"; + until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; + echo "Setting kibana_system password"; + until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done; + echo "All done!"; + ' + healthcheck: + test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] + interval: 1s + timeout: 5s + retries: 120 + backend: build: context: . @@ -53,6 +112,104 @@ services: timeout: 5s retries: 5 + es01: + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + container_name: es01 + depends_on: + setup: + condition: service_healthy + volumes: + - certs:/usr/share/elasticsearch/config/certs:ro + - pong_es_data_01:/usr/share/elasticsearch/data + labels: + co.elastic.logs/module: elasticsearch + ports: + - 9200:9200 + environment: + - node.name=es01 + - cluster.name=${CLUSTER_NAME} + - discovery.type=single-node + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - bootstrap.memory_lock=true + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=true + - xpack.security.http.ssl.key=certs/es01/es01.key + - xpack.security.http.ssl.certificate=certs/es01/es01.crt + - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.enabled=true + - xpack.security.transport.ssl.key=certs/es01/es01.key + - xpack.security.transport.ssl.certificate=certs/es01/es01.crt + - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.verification_mode=certificate + - xpack.license.self_generated.type=${LICENSE} + healthcheck: + test: + [ + "CMD-SHELL", + "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", + ] + interval: 10s + timeout: 10s + retries: 120 + + kibana: + image: docker.elastic.co/kibana/kibana:${STACK_VERSION} + container_name: kibana + labels: + co.elastic.logs/module: kibana + depends_on: + es01: + condition: service_healthy + volumes: + - certs:/usr/share/kibana/config/certs:ro + - pong_kibana:/usr/share/kibana/data + ports: + - 5601:5601 + environment: + - SERVERNAME=kibana + - ELASTICSEARCH_HOSTS=https://es01:9200 + - ELASTICSEARCH_USERNAME=${KIBANA_USERNAME} + - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} + - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt + - XPACK_SECURITY_ENCRYPTIONKEY=${ENCRYPTION_KEY} + - XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${ENCRYPTION_KEY} + - XPACK_REPORTING_ENCRYPTIONKEY=${ENCRYPTION_KEY} + healthcheck: + test: + [ + "CMD-SHELL", + "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'" + ] + interval: 10s + timeout: 10s + retries: 120 + + logstash01: + image: docker.elastic.co/logstash/logstash:${STACK_VERSION} + container_name: logstash01 + labels: + co.elastic.logs/module: logstash + user: root + depends_on: + es01: + condition: service_healthy + kibana: + condition: service_healthy + volumes: + - certs:/usr/share/logstash/certs + - pong_logstash_data01:/usr/share/logstash/data + - ./config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro + - pong_django_logs:/usr/share/logstash/logs + ports: + - "5044:5044/udp" + command: logstash -f /usr/share/logstash/pipeline/logstash.conf + environment: + - NODE_NAME="logstash" + - ELASTIC_HOSTS=https://es01:9200 + - ELASTIC_USER=${ELASTIC_USERNAME} + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - xpack.monitoring.enabled=false + volumes: pong: driver: local @@ -68,6 +225,14 @@ volumes: o: bind pong_pg_data: driver: local + pong_es_data_01: + driver: local + pong_kibana: + driver: local + pong_logstash_data01: + driver: local + certs: + driver: local networks: app-network: diff --git a/docker-compose.yml_old b/docker-compose.yml_old new file mode 100644 index 0000000..aa21870 --- /dev/null +++ b/docker-compose.yml_old @@ -0,0 +1,75 @@ +services: + backend: + build: + context: . + dockerfile: Dockerfile + image: backend + container_name: backend + restart: always + command: /bin/sh -c "sleep 5 && + venv/bin/python manage.py makemigrations --noinput && + venv/bin/python manage.py migrate --noinput && + venv/bin/python manage.py collectstatic --noinput && + venv/bin/daphne -b 0.0.0.0 -p 8080 pong.asgi:application" + volumes: + - pong:/transcendence/pong + - pong_django_logs:/transcendence/logs + ports: + - 8080:8080 + networks: + - app-network + environment: + DB_HOST: db + DB_PORT: 5432 + DB_NAME: ${POSTGRES_DB} + DB_USER: ${POSTGRES_USER} + DB_PASSWORD: ${POSTGRES_PASSWORD} + depends_on: + - db + healthcheck: + test: ["CMD-SHELL", "curl", "http://localhost:8080"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + db: + image: postgres:latest + container_name: postgres + restart: always + volumes: + - pong_pg_data:/var/lib/postgresql/data + ports: + - "5432:5432" + networks: + - app-network + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + pong: + driver: local + driver_opts: + type: none + device: ${PROJECT_PATH} + o: bind + pong_django_logs: + driver: local + driver_opts: + type: none + device: ${DJANGO_LOGS} + o: bind + pong_pg_data: + driver: local + +networks: + app-network: + name: app-network + driver: bridge diff --git a/pong/game/templates/pong/tournament_brackets.html b/pong/game/templates/pong/tournament_brackets.html index f7f0999..ca65553 100644 --- a/pong/game/templates/pong/tournament_brackets.html +++ b/pong/game/templates/pong/tournament_brackets.html @@ -41,14 +41,20 @@
+ {% for round in tournament_rounds %}
+ {% for match in round %}
+ {{ match.player1 }}
+ {{ match.player2|default:"BYE" }}
+ {% endfor %}
+ {% endfor %}
\ No newline at end of file diff --git a/pong/game/tournament.py b/pong/game/tournament.py index 4c45336..4416135 100644 --- a/pong/game/tournament.py +++ b/pong/game/tournament.py @@ -13,12 +13,6 @@ class TournamentMatch(Game): super().__init__(game_id, player1, player2, False) # Store the current game instance in active games match_maker.active_games[game_id] = self - # Set the game for the players - '''player1.set_game(self) - print(f"{player1.user.username} set to game #{self}") - if player2: - player2.set_game(self) - print(f"{player2.user.username} set to game #{self}")''' # Store the tournament instance self.tournament = tournament @@ -36,12 +30,15 @@ class TournamentMatchMaker: self.rounds = [] self.current_round = 0 self.games = 0 - self.tournament_state = "waiting" # Can be "waiting", "in_progress", or "ended" + self.tournament_state = "waiting" #Can be "waiting", "in_progress", or "ended" async def add_player(self, player): if self.tournament_state == "waiting" and player not in self.waiting_players: self.waiting_players.append(player) - print(f"User {player.user.username} joins the TOURNAMENT WAITING ROOM") + if player: + print(f"User {player.user.username} joins the TOURNAMENT WAITING ROOM") + else: + print("BOT joins the TOURNAMENT WAITING ROOM") await self.update_waiting_room() async def update_waiting_room(self): @@ -54,7 +51,7 @@ class TournamentMatchMaker: def generate_waiting_room_html(self): context = { - 'players': [player.user.username for player in self.waiting_players], + 'players': [player.user.username if player else 'BOT' for player in self.waiting_players], 'tournament_state': self.tournament_state, 'players_count': len(self.waiting_players), 'min_players_to_start': 2 # You can adjust this number as needed @@ -62,7 +59,8 @@ class TournamentMatchMaker: return render_to_string('pong/tournament_waiting_room.html', context) async def send_to_player(self, player, data): - await player.send(json.dumps(data)) + if player: + await player.send(json.dumps(data)) async def remove_player(self, player): if player in self.waiting_players: @@ -72,7 +70,9 @@ class TournamentMatchMaker: # Tournament start method async def start_tournament(self): if len(self.waiting_players) < 2: - return False + return False + if len(self.waiting_players) % 2 == 0: + await self.add_player(None) self.tournament_state = "in_progress" random.shuffle(self.waiting_players) self.current_round = 0 @@ -108,13 +108,15 @@ class TournamentMatchMaker: matches.append(match) else: # Create a BYE match where the second player is None - match = TournamentMatch(self.games, players[i], None, self) # BYE match + match = TournamentMatch(self.games, players[i], None, self) # BYE match matches.append(match) # Assign the new match instance to the players - await players[i].set_game(match) + if players[i]: + await players[i].set_game(match) if i + 1 < len(players): - await players[i + 1].set_game(match) + if players[i + 1]: + await players[i + 1].set_game(match) self.rounds.append(matches) self.matches.extend(matches) @@ -157,10 +159,10 @@ class TournamentMatchMaker: elif match.player1: # Handle BYE match await match_maker.notify_players(match.player1, match.player2, match.game_id, False) - match.game_state['player1_score'] = 3 + asyncio.create_task(match.start_game()) + '''match.game_state['player1_score'] = 3 match.game_state['player2_score'] = 0 - await match.end_game() - #asyncio.create_task(match.start_game()) + await match.end_game()''' def get_round_winners(self): winners = [] diff --git a/pong/settings.py b/pong/settings.py index 446ec08..b44ccdf 100644 --- a/pong/settings.py +++ b/pong/settings.py @@ -136,7 +136,7 @@ CHANNEL_LAYERS = { }, } -'''LOGGING = { +LOGGING = { 'version': 1, # The version of the logging configuration schema 'disable_existing_loggers': False, # Allows existing loggers to keep logging 'formatters': { # Defines how log messages will be formatted @@ -169,4 +169,4 @@ CHANNEL_LAYERS = { 'propagate': True, # If True, messages will be passed to the parent loggers as well }, }, -}''' +} From 8ad33f8acb6eb238489872aee9a6af70015732c4 Mon Sep 17 00:00:00 2001 From: CHIBOUB Chakib Date: Tue, 10 Sep 2024 16:49:10 +0200 Subject: [PATCH 2/3] fixed tournament byes --- pong/game/game.py | 5 +++-- .../pong/tournament_waiting_room.html | 2 +- pong/game/tournament.py | 21 ++++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/pong/game/game.py b/pong/game/game.py index 2235970..1e77fdf 100644 --- a/pong/game/game.py +++ b/pong/game/game.py @@ -27,9 +27,10 @@ class Game: 'game_text': '' } else: - self.botgame = player2 is None + # Set botgame to True if either player1 or player2 is None + self.botgame = player1 is None or player2 is None self.game_state = { - 'player1_name': player1.user.username, + 'player1_name': player1.user.username if player1 else 'BOT', 'player2_name': player2.user.username if player2 else 'BOT', 'player1_position': 150, 'player2_position': 150, diff --git a/pong/game/templates/pong/tournament_waiting_room.html b/pong/game/templates/pong/tournament_waiting_room.html index cb77338..4b635c3 100644 --- a/pong/game/templates/pong/tournament_waiting_room.html +++ b/pong/game/templates/pong/tournament_waiting_room.html @@ -1,4 +1,4 @@ - +jik

Tournament Waiting Room

diff --git a/pong/game/tournament.py b/pong/game/tournament.py index 4416135..dfea67b 100644 --- a/pong/game/tournament.py +++ b/pong/game/tournament.py @@ -21,7 +21,8 @@ class TournamentMatch(Game): await super().end_game(disconnected_player) # Handle the end of the match in the tournament context await self.tournament.handle_match_end(self) - del match_maker.active_games[self.game_id] + if self.game_id in match_maker.active_games: + del match_maker.active_games[self.game_id] class TournamentMatchMaker: def __init__(self): @@ -51,10 +52,10 @@ class TournamentMatchMaker: def generate_waiting_room_html(self): context = { - 'players': [player.user.username if player else 'BOT' for player in self.waiting_players], + 'players': [player.user.username if player else 'BYE' for player in self.waiting_players], 'tournament_state': self.tournament_state, 'players_count': len(self.waiting_players), - 'min_players_to_start': 2 # You can adjust this number as needed + 'min_players_to_start': 3 # You can adjust this number as needed } return render_to_string('pong/tournament_waiting_room.html', context) @@ -139,8 +140,8 @@ class TournamentMatchMaker: return [ [ { - 'player1': match.player1.user.username if match.player1 else 'BOT', - 'player2': match.player2.user.username if match.player2 else 'BOT', + 'player1': match.player1.user.username if match.player1 else 'BYE', + 'player2': match.player2.user.username if match.player2 else 'BYE', 'winner': match.game_state['player1_name'] if match.game_state['player1_score'] > match.game_state['player2_score'] else match.game_state['player2_name'] if match.ended else None, 'score1': match.game_state['player1_score'], 'score2': match.game_state['player2_score'] @@ -159,18 +160,18 @@ class TournamentMatchMaker: elif match.player1: # Handle BYE match await match_maker.notify_players(match.player1, match.player2, match.game_id, False) - asyncio.create_task(match.start_game()) - '''match.game_state['player1_score'] = 3 + #asyncio.create_task(match.start_game()) + match.game_state['player1_score'] = 3 match.game_state['player2_score'] = 0 - await match.end_game()''' + await match.end_game() def get_round_winners(self): winners = [] for match in self.rounds[-1]: if match.ended: winner = match.player1 if match.game_state['player1_score'] > match.game_state['player2_score'] else match.player2 - if winner: - winners.append(winner) + #if winner: + winners.append(winner) return winners async def end_tournament(self, winner): From c6cb11d2f842ec7bab706b362d4da29265055e11 Mon Sep 17 00:00:00 2001 From: CHIBOUB Chakib Date: Tue, 10 Sep 2024 17:23:54 +0200 Subject: [PATCH 3/3] handle tournament end game's --- pong/game/game.py | 11 +++++++++-- pong/game/templates/pong/tournament_waiting_room.html | 2 +- pong/game/tournament.py | 8 ++++++++ pong/game/utils.py | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pong/game/game.py b/pong/game/game.py index 1e77fdf..f8b6059 100644 --- a/pong/game/game.py +++ b/pong/game/game.py @@ -4,8 +4,9 @@ import json import asyncio import random from datetime import datetime -from .utils import handle_game_data +from .utils import handle_game_data, getlen from asgiref.sync import sync_to_async +from .models import Tournoi class Game: def __init__(self, game_id, player1, player2, localgame): @@ -242,6 +243,12 @@ class Game: if not self.botgame: if not self.localgame: await self.player2.send(end_message) - await sync_to_async(handle_game_data)(self.game_state['player1_name'], self.game_state['player2_name'], + if hasattr(self, 'tournament'): + len_tournament = await sync_to_async(getlen)() + await sync_to_async(handle_game_data)(self.game_state['player1_name'], self.game_state['player2_name'], + self.game_state['player1_score'], self.game_state['player2_score'], + self.bt1, self.bt2, duration, True, self.tournament.name + " #" + str(len_tournament + 1)) + else: + await sync_to_async(handle_game_data)(self.game_state['player1_name'], self.game_state['player2_name'], self.game_state['player1_score'], self.game_state['player2_score'], self.bt1, self.bt2, duration, False, None) diff --git a/pong/game/templates/pong/tournament_waiting_room.html b/pong/game/templates/pong/tournament_waiting_room.html index 4b635c3..cb77338 100644 --- a/pong/game/templates/pong/tournament_waiting_room.html +++ b/pong/game/templates/pong/tournament_waiting_room.html @@ -1,4 +1,4 @@ -jik +

Tournament Waiting Room

diff --git a/pong/game/tournament.py b/pong/game/tournament.py index dfea67b..c2b944c 100644 --- a/pong/game/tournament.py +++ b/pong/game/tournament.py @@ -7,6 +7,12 @@ import random from .matchmaking import match_maker from .game import Game +TOURNAMENT_NAMES = [ + "Champion's Clash", "Ultimate Showdown", "Battle Royale", + "Victory's Cup", "Legends Tournament", "Elite Series", "Clash of 42", + "Shibuya Incident", "Cunning Game", "Elite of the Stars", "Chaku's Disciples" +] + class TournamentMatch(Game): def __init__(self, game_id, player1, player2, tournament): # Initialize the parent Game class with the provided parameters @@ -32,6 +38,7 @@ class TournamentMatchMaker: self.current_round = 0 self.games = 0 self.tournament_state = "waiting" #Can be "waiting", "in_progress", or "ended" + self.name = random.choice(TOURNAMENT_NAMES) async def add_player(self, player): if self.tournament_state == "waiting" and player not in self.waiting_players: @@ -70,6 +77,7 @@ class TournamentMatchMaker: # Tournament start method async def start_tournament(self): + if len(self.waiting_players) < 2: return False if len(self.waiting_players) % 2 == 0: diff --git a/pong/game/utils.py b/pong/game/utils.py index d30ae3f..8e9c2db 100644 --- a/pong/game/utils.py +++ b/pong/game/utils.py @@ -172,3 +172,5 @@ def get_player_p_win(player_name): player = get_object_or_404(Player, name=player_name) return player.p_win +def getlen(): + return Tournoi.objects.count()