Updating event listeners and API to use the new library
This commit is contained in:
@@ -47,29 +47,14 @@ async def get_rcon_manager():
|
|||||||
# FastAPI Endpoint to List Players
|
# FastAPI Endpoint to List Players
|
||||||
@app.get("/players")
|
@app.get("/players")
|
||||||
async def list_players(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
async def list_players(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
||||||
try:
|
response = await rcon.fetch_players()
|
||||||
response = await rcon.send_command("players")
|
return {"response": response}
|
||||||
players = []
|
|
||||||
for line in response.splitlines():
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) >= 2:
|
|
||||||
name = parts[0]
|
|
||||||
try:
|
|
||||||
score = int(parts[1])
|
|
||||||
except ValueError:
|
|
||||||
score = 0
|
|
||||||
player = Player(name=name, score=score)
|
|
||||||
players.append(player)
|
|
||||||
return players
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"Error fetching players: {e}")
|
|
||||||
raise HTTPException(status_code=500, detail="Error fetching players")
|
|
||||||
|
|
||||||
# Kick Player Endpoint
|
# Kick Player Endpoint
|
||||||
@app.post("/kick")
|
@app.post("/kick")
|
||||||
async def kick_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
async def kick_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
||||||
try:
|
try:
|
||||||
response = await rcon.send_command(f'kick {action.playerid} {action.reason}')
|
response = await rcon.kick(f'{action.playerid} {action.reason}')
|
||||||
return {"response": response}
|
return {"response": response}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error kicking player: {e}")
|
log.error(f"Error kicking player: {e}")
|
||||||
@@ -80,7 +65,7 @@ async def kick_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends
|
|||||||
async def ban_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
async def ban_player(action: PlayerAction, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
||||||
try:
|
try:
|
||||||
duration_str = f"{action.duration} " if action.duration else ""
|
duration_str = f"{action.duration} " if action.duration else ""
|
||||||
response = await rcon.send_command(f'ban {action.playerid} {duration_str}"{action.reason}"')
|
response = await rcon.ban(f'{action.playerid} {duration_str}"{action.reason}"')
|
||||||
return {"response": response}
|
return {"response": response}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error banning player: {e}")
|
log.error(f"Error banning player: {e}")
|
||||||
@@ -100,7 +85,7 @@ async def unlock_server(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
|||||||
@app.post("/global_message")
|
@app.post("/global_message")
|
||||||
async def global_message(message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
async def global_message(message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
||||||
try:
|
try:
|
||||||
response = await rcon.send_command(f'Say -1 {message}')
|
response = await rcon.send(f'{message}')
|
||||||
return {"response": response}
|
return {"response": response}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error sending global message: {e}")
|
log.error(f"Error sending global message: {e}")
|
||||||
@@ -110,7 +95,7 @@ async def global_message(message: str, rcon: rcon.AsyncRCONClient = Depends(get_
|
|||||||
@app.post("/direct_message")
|
@app.post("/direct_message")
|
||||||
async def direct_message(playerid: str, message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
async def direct_message(playerid: str, message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)):
|
||||||
try:
|
try:
|
||||||
response = await rcon.send_command(f'Say {playerid} {message}')
|
response = await rcon.whisper(f'{playerid} {message}')
|
||||||
return {"response": response}
|
return {"response": response}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error sending direct message: {e}")
|
log.error(f"Error sending direct message: {e}")
|
||||||
@@ -144,3 +129,4 @@ async def server_response_to_command(response: str):
|
|||||||
# Main Function to Run FastAPI App
|
# Main Function to Run FastAPI App
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||||
|
asyncio.run(get_rcon_manager())
|
||||||
51
listener.py
51
listener.py
@@ -1,51 +0,0 @@
|
|||||||
"""Listens to an RCON server for messages."""
|
|
||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
import math
|
|
||||||
|
|
||||||
import berconpy as rcon
|
|
||||||
|
|
||||||
IP = "217.72.204.88"
|
|
||||||
PORT = 2313
|
|
||||||
PASSWORD = "u1BSlMM4LH0"
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
client = rcon.AsyncRCONClient()
|
|
||||||
|
|
||||||
|
|
||||||
@client.dispatch.on_login
|
|
||||||
async def on_login():
|
|
||||||
print("on_login")
|
|
||||||
|
|
||||||
|
|
||||||
@client.dispatch.on_message
|
|
||||||
async def on_message(message: str):
|
|
||||||
print("on_message:", message)
|
|
||||||
|
|
||||||
|
|
||||||
@client.dispatch.on_command
|
|
||||||
async def server_response_to_command(response: str):
|
|
||||||
# this event also includes keep alive commands we send to the server;
|
|
||||||
# for handling commands, reading the return value of
|
|
||||||
# `await client.send_command()` is the recommended method
|
|
||||||
if not response:
|
|
||||||
return print("on_command: <empty>")
|
|
||||||
|
|
||||||
print("on_command:", response)
|
|
||||||
|
|
||||||
|
|
||||||
# Other events are documented in AsyncRCONClient
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
async with client.connect(IP, PORT, PASSWORD):
|
|
||||||
await asyncio.sleep(math.inf)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(main())
|
|
||||||
139
main.py
Normal file
139
main.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
import json
|
||||||
|
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()
|
||||||
|
|
||||||
|
# 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
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize RCON client
|
||||||
|
client = rcon.AsyncRCONClient()
|
||||||
|
|
||||||
|
# Message store
|
||||||
|
messages = []
|
||||||
|
player_connect_messages = []
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
@client.dispatch.on_command
|
||||||
|
async def server_response_to_command(response: str):
|
||||||
|
print('Command response:', response)
|
||||||
|
messages.append(response)
|
||||||
|
|
||||||
|
# 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(3600) # Sleep for an hour and then check the connection
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in RCON client: {e}")
|
||||||
|
finally:
|
||||||
|
await client.close()
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
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"})
|
||||||
|
|
||||||
|
# API endpoint to kick a player
|
||||||
|
@app.post("/kick")
|
||||||
|
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")
|
||||||
|
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"})
|
||||||
|
|
||||||
|
# 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"})
|
||||||
|
|
||||||
|
# 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)
|
||||||
98
tester.html
Normal file
98
tester.html
Normal 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>
|
||||||
Reference in New Issue
Block a user