diff --git a/api.py b/api_OLREF.py similarity index 81% rename from api.py rename to api_OLREF.py index 7985010..6bb9021 100644 --- a/api.py +++ b/api_OLREF.py @@ -47,29 +47,14 @@ async def get_rcon_manager(): # FastAPI Endpoint to List Players @app.get("/players") async def list_players(rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)): - try: - response = await rcon.send_command("players") - 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") + 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.send_command(f'kick {action.playerid} {action.reason}') + response = await rcon.kick(f'{action.playerid} {action.reason}') return {"response": response} except Exception as 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)): try: 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} except Exception as 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") async def global_message(message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)): try: - response = await rcon.send_command(f'Say -1 {message}') + response = await rcon.send(f'{message}') return {"response": response} except Exception as 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") async def direct_message(playerid: str, message: str, rcon: rcon.AsyncRCONClient = Depends(get_rcon_manager)): try: - response = await rcon.send_command(f'Say {playerid} {message}') + response = await rcon.whisper(f'{playerid} {message}') return {"response": response} except Exception as 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 if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) + asyncio.run(get_rcon_manager()) \ No newline at end of file diff --git a/listener.py b/listener.py deleted file mode 100644 index 73dddc3..0000000 --- a/listener.py +++ /dev/null @@ -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: ") - - 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()) \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..4d9bb9c --- /dev/null +++ b/main.py @@ -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) diff --git a/tester.html b/tester.html new file mode 100644 index 0000000..e4d5d85 --- /dev/null +++ b/tester.html @@ -0,0 +1,98 @@ + + + + + + Player Connect Messages + + + +

Player Connect Messages

+
Current Players: 0
+
+ + + +