Compare commits

...

5 Commits

Author SHA1 Message Date
26ce03cdf6 Update 2024-10-20 16:17:47 +02:00
a791803aec typo in readme 2024-06-14 03:33:28 +02:00
ef3c2fc1d3 Updating event listeners and API to use the new library 2024-06-14 03:30:10 +02:00
20c2e1ae3c Fixed wrong naming of the listener file 2024-06-13 00:07:53 +02:00
1b897a70a9 Switched to berconpy, implemented listener 2024-06-13 00:07:40 +02:00
11 changed files with 515 additions and 346 deletions

34
.dockerignore Normal file
View File

@@ -0,0 +1,34 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.DS_Store
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

5
.gitignore vendored
View File

@@ -1 +1,4 @@
credentials.json
credentials.json
\venv\
*.env
\__pycache__\

51
Dockerfile Normal file
View File

@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:1
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/
# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7
ARG PYTHON_VERSION=3.11.9
FROM python:${PYTHON_VERSION}-slim as base
# Prevents Python from writing pyc files.
ENV PYTHONDONTWRITEBYTECODE=1
# Keeps Python from buffering stdout and stderr to avoid situations where
# the application crashes without emitting any logs due to buffering.
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
# Leverage a bind mount to requirements.txt to avoid having to copy them into
# into this layer.
RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=bind,source=requirements.txt,target=requirements.txt \
python -m pip install -r requirements.txt
# Switch to the non-privileged user to run the application.
USER appuser
# Copy the source code into the container.
COPY . .
# Expose the port that the application listens on.
EXPOSE 8000
# Run the application.
CMD python main.py

View File

@@ -1,296 +0,0 @@
from rcon.battleye import Client
from rcon.battleye import Client, ServerMessage
import sys
import os
import json
import socket
from time import sleep
# Define the server details
SERVER_ADDRESS = ''
SERVER_PORT = 0
RCON_PASSWORD = ''
# Check if credentials file exists
if os.path.exists('credentials.json'):
# Load credentials from file
with open('credentials.json', 'r') as file:
credentials = json.load(file)
SERVER_ADDRESS = credentials.get('SERVER_ADDRESS', '')
SERVER_PORT = credentials.get('SERVER_PORT', 0)
RCON_PASSWORD = credentials.get('RCON_PASSWORD', '')
else:
# Generate example credentials file
credentials = {
'SERVER_ADDRESS': 'YOUR-SERVER-ADDRESS', # Example Values
'SERVER_PORT': 2303, # Example Values
'RCON_PASSWORD': 'RCON_PASSWORD' # Example Values
}
with open('credentials.json', 'w') as file:
json.dump(credentials, file, indent=4)
print("Please fill in the server details in the credentials.json file.")
sys.exit()
def print_menu():
print()
print("1. List Players")
print("2. Messaging")
print("3. Locking")
print("4. Kicking")
print("5. Banning")
print("6. Server menu")
print("7. Exit")
def handle_input(choice):
if choice == "1":
list_players()
elif choice == "2":
print_message_menu()
message_choice = input("Enter your choice: ")
handle_message_input(message_choice)
elif choice == "3":
print_locking_menu()
locking_choice = input("Enter your choice: ")
handle_locking_input(locking_choice)
elif choice == "4":
print_kick_menu()
kick_choice = input("Enter your choice: ")
handle_kick_input(kick_choice)
elif choice == "5":
print_banning_menu()
banning_choice = input("Enter your choice: ")
handle_banning_input(banning_choice)
elif choice == "6":
print_server_menu()
server_choice = input("Enter your choice: ")
handle_server_input(server_choice)
elif choice == "7":
sys.exit()
else:
print("Invalid choice. Please try again.")
def print_message_menu():
print("1. Send Global Message")
print("2. Send Direct Message")
print("3. Back")
def print_server_menu():
print("1. Soft Server Restart (Restart within 3 minutes with warning messages sent to the players)")
print("2. Hard Server Restart (Restart immediately without warning messages)")
print("3. Back")
def print_locking_menu():
print("1. Lock Server")
print("2. Unlock Server")
print("3. Back")
def print_kick_menu():
print("1. Kick Single Player")
print("2. Kick All Players")
print("3. Back")
def print_banning_menu():
print("1. Show Banlist")
print("2. Ban Player")
print("3. Ban Player by SteamID")
print("4. Unban Player")
print("5. Back")
def handle_message_input(choice):
if choice == "1":
send_global_message()
elif choice == "2":
send_direct_message()
elif choice == "3":
print_menu()
else:
print("Invalid choice. Please try again.")
def handle_locking_input(choice):
if choice == "1":
lock_server()
elif choice == "2":
unlock_server()
elif choice == "3":
print_menu()
else:
print("Invalid choice. Please try again.")
def handle_kick_input(choice):
if choice == "1":
kick_single_player()
elif choice == "2":
kick_all_players()
elif choice == "3":
print_menu()
else:
print("Invalid choice. Please try again.")
def handle_banning_input(choice):
if choice == "1":
show_banlist()
elif choice == "2":
ban_player()
elif choice == "3":
ban_player_by_steamid()
elif choice == "4":
unban_player()
elif choice == "5":
print_menu()
else:
print("Invalid choice. Please try again.")
def handle_server_input(choice):
if choice == "1":
soft_restart()
elif choice == "2":
confirm = input("Are you sure you want to perform a hard restart? (y/n): ")
if confirm.lower() == "y":
hard_restart()
else:
print("Hard restart cancelled.")
elif choice == "3":
print_menu()
else:
print("Invalid choice. Please try again.")
def send_global_message():
message = input("Enter the message to send: ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'Say -1 {message}')
print(response)
def send_direct_message():
list_players()
player_name = input("Enter the # (number) of the player to message: ")
message = input("Enter the message to send: ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'Say -{player_name} {message}')
print(response)
def hard_restart():
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('#shutdown')
print(response)
def soft_restart(): # Not implemented yet
print('not implemented yet')
pass
def list_players():
try:
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('players')
print(response)
except socket.timeout:
print("Connection timed out. Please check the server address, port, and network settings.")
except Exception as e:
print(f"An error occurred: {e}")
def kick_single_player():
list_players()
player_name = input("Enter the # (number) of the player to kick: ")
reason = input("Enter the reason for kicking the player (can be empty): ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'kick {player_name} "{reason}"')
if not response:
print("Player kicked successfully.")
else:
print(response)
def kick_all_players():
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('#kick -1')
print(response)
def show_banlist():
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('Bans')
print(response)
def ban_player():
list_players()
player_name = input("Enter the # (number) of the player to ban: ")
ban_time = input("Enter the ban time in minutes: ")
reason = input("Enter the reason for banning the player (can be empty): ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'ban {player_name} {ban_time} "{reason}"')
if not response:
print("Player banned successfully.")
else:
print(response)
def server_monitor():
while True:
try:
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('status')
print(response)
except socket.timeout:
print("Connection timed out. Please check the server address, port, and network settings.")
except Exception as e:
print(f"An error occurred: {e}")
sleep(30)
def ban_player_by_steamid():
steamid = input("Enter the SteamID of the player to ban: ")
ban_time = input("Enter the ban time in minutes: ")
reason = input("Enter the reason for banning the player (can be empty): ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'ban -1 {ban_time} "{reason}" {steamid}')
if not response:
print("Player banned successfully.")
else:
print(response)
def unban_player():
show_banlist()
ban_id = input("Enter the # (number) of the ban to remove: ")
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run(f'removeBan {ban_id}')
if not response:
print("Ban removed successfully.")
else:
print(response)
def lock_server():
try:
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('#lock')
print(response)
except socket.timeout:
print("Connection timed out. Please check the server address, port, and network settings.")
except Exception as e:
print(f"An error occurred: {e}")
def unlock_server():
try:
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('#unlock')
print(response)
except socket.timeout:
print("Connection timed out. Please check the server address, port, and network settings.")
except Exception as e:
print(f"An error occurred: {e}")
def list_players():
try:
with Client(SERVER_ADDRESS, SERVER_PORT, passwd=RCON_PASSWORD) as client:
response = client.run('players')
print(response)
except socket.timeout:
print("Connection timed out. Please check the server address, port, and network settings.")
except Exception as e:
print(f"An error occurred: {e}")
def create_cli():
while True:
print_menu()
choice = input("Enter your choice: ")
handle_input(choice)
if __name__ == "__main__":
create_cli()

22
README.Docker.md Normal file
View File

@@ -0,0 +1,22 @@
### Building and running your application
When you're ready, start your application by running:
`docker compose up --build`.
Your application will be available at http://localhost:8000.
### Deploying your application to the cloud
First, build your image, e.g.: `docker build -t myapp .`.
If your cloud uses a different CPU architecture than your development
machine (e.g., you are on a Mac M1 and your cloud provider is amd64),
you'll want to build the image for that platform, e.g.:
`docker build --platform=linux/amd64 -t myapp .`.
Then, push it to your registry, e.g. `docker push myregistry.com/myapp`.
Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/)
docs for more detail on building and pushing.
### References
* [Docker's Python guide](https://docs.docker.com/language/python/)

View File

@@ -1,3 +1,6 @@
## This is the API Branch of this project.
The main goal is to provide an RCON backend that can be used by another container (Werbserver)
## DayZ Server Management Tool
This project is a Python tool for managing a DayZ server using the BattlEye RCON protocol. Key features include:

132
api_OLREF.py Normal file
View File

@@ -0,0 +1,132 @@
import asyncio
import logging
import uvicorn
import json
import os
from pydantic import BaseModel
import berconpy as rcon
from fastapi import FastAPI, HTTPException, Depends
# RCON Server Details
credentials_file = os.path.join(os.path.dirname(__file__), "credentials.json")
with open(credentials_file) as f:
credentials = json.load(f)
IP_ADDR = credentials["SERVER_ADDRESS"]
PORT = credentials["SERVER_PORT"]
PASSWORD = credentials["RCON_PASSWORD"]
# Logging Configuration
log = logging.getLogger("berconpy")
log.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
log.addHandler(handler)
# RCON Client Initialization
client = rcon.AsyncRCONClient()
# FastAPI Initialization
app = FastAPI()
# Player Model
class Player(BaseModel):
name: str
score: int
class PlayerAction(BaseModel):
playerid: str
reason: str
duration: int = None # Optional for ban duration
# Dependency to get RCON manager
async def get_rcon_manager():
async with client.connect(IP_ADDR, PORT, PASSWORD):
yield client
# FastAPI Endpoint to List Players
@app.get("/players")
async def list_players(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
response = await rcon.fetch_players()
return {"response": response}
# Kick Player Endpoint
@app.post("/kick")
async def kick_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
response = await rcon.kick(f'{action.playerid} {action.reason}')
return {"response": response}
except Exception as e:
log.error(f"Error kicking player: {e}")
raise HTTPException(status_code=500, detail="Error kicking player")
# Ban Player Endpoint
@app.post("/ban")
async def ban_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
duration_str = f"{action.duration} " if action.duration else ""
response = await rcon.ban(f'{action.playerid} {duration_str}"{action.reason}"')
return {"response": response}
except Exception as e:
log.error(f"Error banning player: {e}")
raise HTTPException(status_code=500, detail="Error banning player")
# Unlock Server Endpoint
@app.post("/unlock")
async def unlock_server(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
response = await rcon.send_command('#unlock')
return {"response": response}
except Exception as e:
log.error(f"Error unlocking server: {e}")
raise HTTPException(status_code=500, detail="Error unlocking server")
# Global Message Endpoint
@app.post("/global_message")
async def global_message(message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
response = await rcon.send(f'{message}')
return {"response": response}
except Exception as e:
log.error(f"Error sending global message: {e}")
raise HTTPException(status_code=500, detail="Error sending global message")
# Direct Message Endpoint
@app.post("/direct_message")
async def direct_message(playerid: str, message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
response = await rcon.whisper(f'{playerid} {message}')
return {"response": response}
except Exception as e:
log.error(f"Error sending direct message: {e}")
raise HTTPException(status_code=500, detail="Error sending direct message")
# Lock Server Endpoint
@app.post("/lock")
async def lock_server(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
try:
response = await rcon.send_command('#lock')
return {"response": response}
except Exception as e:
log.error(f"Error locking server: {e}")
raise HTTPException(status_code=500, detail="Error locking server")
# RCON Event Handlers
@client.dispatch.on_login
async def on_login():
print("Connected to RCON server.")
@client.dispatch.on_message
async def on_message(message: str):
print("Received message from server:", message)
@client.dispatch.on_command
async def server_response_to_command(response: str):
if not response:
return print("on_command: <empty>")
print("on_command:", response)
# Main Function to Run FastAPI App
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
asyncio.run(get_rcon_manager())

49
compose.yaml Normal file
View File

@@ -0,0 +1,49 @@
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
ports:
- 8000:8000
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt

169
main.py
View File

@@ -1,66 +1,139 @@
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import json
from rcon.battleye import Client
import os
import asyncio
from typing import List, Dict, Any
from fastapi.responses import JSONResponse
import berconpy as rcon
# RCON Server Details
credentials_file = os.path.join(os.path.dirname(__file__), "credentials.json")
try:
with open(credentials_file) as f:
credentials = json.load(f)
except FileNotFoundError:
raise Exception(f"Credentials file not found: {credentials_file}")
except json.JSONDecodeError:
raise Exception(f"Error decoding credentials file: {credentials_file}")
IP_ADDR = credentials["SERVER_ADDRESS"]
PORT = credentials["SERVER_PORT"]
PASSWORD = credentials["RCON_PASSWORD"]
# Initialize FastAPI app
app = FastAPI()
# Load credentials
credentials_file = 'credentials.json'
with open(credentials_file, 'r') as file:
credentials = json.load(file)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allow all origins
allow_credentials=True,
allow_methods=["*"], # Allow all methods
allow_headers=["*"], # Allow all headers
)
SERVER_ADDRESS = credentials.get('SERVER_ADDRESS', '')
SERVER_PORT = credentials.get('SERVER_PORT', 0)
RCON_PASSWORD = credentials.get('RCON_PASSWORD', '')
# Initialize RCON client
client = rcon.AsyncRCONClient()
class RCONManager:
def __init__(self, address, port, password):
self.client = Client(address, port, passwd=password)
self.client.connect()
# Message store
messages = []
player_connect_messages = []
def run(self, command):
return self.client.run(command)
# Event handler for player connect messages
@client.dispatch.on_message
async def on_player_connect(player_connect_message: str):
print('Player connected:', player_connect_message)
player_connect_messages.append(player_connect_message)
def close(self):
self.client.disconnect()
@client.dispatch.on_command
async def server_response_to_command(response: str):
print('Command response:', response)
messages.append(response)
rcon_manager = RCONManager(SERVER_ADDRESS, SERVER_PORT, RCON_PASSWORD)
# Background task to run the RCON client
async def run_rcon_client():
try:
async with client.connect(IP_ADDR, PORT, PASSWORD):
while True:
await asyncio.sleep(60) # Sleep for an hour and then check the connection
except Exception as e:
print(f"Error in RCON client: {e}")
finally:
await client.close()
@app.on_event("shutdown")
def shutdown_event():
rcon_manager.close()
class PlayerAction(BaseModel):
steamid: str
reason: str
duration: int
def get_rcon_manager():
return rcon_manager
# API endpoint to get messages
@app.get("/loginmessages", response_class=JSONResponse)
async def get_messages() -> List[str]:
return player_connect_messages
# API endpoint to get players list
@app.get("/players")
def list_players(rcon: RCONManager = Depends(get_rcon_manager)):
response = rcon.run('players')
return {"response": response}
async def get_players() -> List[Dict[str, Any]]:
try:
players = await client.fetch_players()
player_list = [{"id": player.id, "name": player.name} for player in players]
return JSONResponse(content=player_list)
except Exception as e:
print(f"Error fetching players: {e}")
return JSONResponse(status_code=500, content={"message": "Error fetching players"})
# Ähnliche Änderungen für die anderen Endpunkte anwenden
# API endpoint to kick a player
@app.post("/kick")
def kick_player(action: PlayerAction, rcon: RCONManager = Depends(get_rcon_manager)):
response = rcon.run(f'kick {action.steamid} {action.reason}')
return {"response": response}
async def kick_player(player_id: int, reason: str = ""):
try:
response = await client.kick(player_id, reason)
return JSONResponse(content={"message": response})
except Exception as e:
print(f"Error kicking player: {e}")
return JSONResponse(status_code=500, content={"message": "Error kicking player"})
# API endpoint to ban a player
@app.post("/ban")
def ban_player(action: PlayerAction, rcon: RCONManager = Depends(get_rcon_manager)):
response = rcon.run(f'ban {action.steamid} {action.duration} "{action.reason}"')
return {"response": response}
async def ban_player(addr: str, duration: int = 0, reason: str = ""):
try:
response = await client.ban(addr, duration, reason)
return JSONResponse(content={"message": response})
except Exception as e:
print(f"Error banning player: {e}")
return JSONResponse(status_code=500, content={"message": "Error banning player"})
@app.post("/unlock")
def unlock_server(rcon: RCONManager = Depends(get_rcon_manager)):
response = rcon.run('#unlock')
return {"response": response}
# API endpoint to send a global message
@app.post("/message")
async def send_global_message(message: str):
try:
response = await client.send(message)
return JSONResponse(content={"message": response})
except Exception as e:
print(f"Error sending message: {e}")
return JSONResponse(status_code=500, content={"message": "Error sending message"})
@app.post("/lock")
def lock_server(rcon: RCONManager = Depends(get_rcon_manager)):
response = rcon.run('#lock')
return {"response": response}
# API endpoint to unban a player
@app.post("/unban")
async def unban_player(ban_id: int):
try:
response = await client.unban(ban_id)
return JSONResponse(content={"message": response})
except Exception as e:
print(f"Error unbanning player: {e}")
return JSONResponse(status_code=500, content={"message": "Error unbanning player"})
# API endpoint to send a private message (whisper) to a player
@app.post("/whisper")
async def whisper_player(player_id: int, message: str):
try:
response = await client.whisper(player_id, message)
return JSONResponse(content={"message": response})
except Exception as e:
print(f"Error sending whisper: {e}")
return JSONResponse(status_code=500, content={"message": "Error sending whisper"})
# Start the RCON client in the background when the app starts
@app.on_event("startup")
async def startup_event():
asyncio.create_task(run_rcon_client())
# Main entry point for running the FastAPI app
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

View File

@@ -1,4 +1,4 @@
fastapi
uvicorn[standard]
rcon
berconpy
pydantic

98
tester.html Normal file
View File

@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Player Connect Messages</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
#messages {
border: 1px solid #ccc;
padding: 10px;
height: 400px;
overflow-y: scroll;
}
.message {
border-bottom: 1px solid #eee;
padding: 5px 0;
}
#player-count {
font-size: 20px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>Player Connect Messages</h1>
<div id="player-count">Current Players: 0</div>
<div id="messages"></div>
<script>
function fetchMessages() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8000/loginmessages', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
const data = JSON.parse(xhr.responseText);
console.log('Fetched messages:', data);
updateMessages(data);
} else {
console.error('Error fetching messages:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network error while fetching messages');
};
xhr.send();
}
function fetchPlayerCount() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8000/players', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
const data = JSON.parse(xhr.responseText);
console.log('Fetched player count:', data.length);
updatePlayerCount(data.length);
} else {
console.error('Error fetching player count:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network error while fetching player count');
};
xhr.send();
}
function updateMessages(messages) {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML = '';
messages.forEach(message => {
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
messageDiv.textContent = message;
messagesDiv.appendChild(messageDiv);
});
console.log('Updated messages displayed');
}
function updatePlayerCount(count) {
const playerCountDiv = document.getElementById('player-count');
playerCountDiv.textContent = `Current Players: ${count}`;
}
// Fetch messages every 5 seconds
setInterval(fetchMessages, 5000);
// Fetch player count every 5 seconds
setInterval(fetchPlayerCount, 5000);
// Initial fetch
fetchMessages();
fetchPlayerCount();
</script>
</body>
</html>