2024-02-27 23:02:03 -05:00
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
|
|
|
|
import websockets
|
|
|
|
from pydactyl import PterodactylClient, exceptions
|
|
|
|
from redbot.core import Config, commands
|
|
|
|
from redbot.core.bot import Red
|
|
|
|
|
|
|
|
|
|
|
|
class Pterodactyl(commands.Cog):
|
|
|
|
"""Pterodactyl allows you to manage your Pterodactyl Panel from Discord."""
|
|
|
|
|
|
|
|
def __init__(self, bot: Red):
|
|
|
|
self.bot = bot
|
2024-02-27 23:18:17 -05:00
|
|
|
self.config = Config.get_conf(self, identifier=457581387213637448123567, force_registration=True)
|
2024-02-27 23:02:03 -05:00
|
|
|
self.config.register_global(
|
2024-02-27 23:18:17 -05:00
|
|
|
base_url=None,
|
|
|
|
api_key=None,
|
|
|
|
server_id=None,
|
2024-02-27 23:02:03 -05:00
|
|
|
startup_jar=None,
|
|
|
|
startup_arguments=None,
|
|
|
|
power_action_in_progress=False
|
|
|
|
)
|
|
|
|
self.logger = logging.getLogger('red.sea.pterodactyl')
|
|
|
|
self.client = None
|
2024-02-28 08:47:24 -05:00
|
|
|
self.task = None
|
2024-02-27 23:02:03 -05:00
|
|
|
self.websocket = None
|
|
|
|
|
2024-02-28 08:11:15 -05:00
|
|
|
async def establish_websocket_connection(self):
|
2024-02-28 08:49:02 -05:00
|
|
|
self.logger.debug("Establishing WebSocket connection")
|
2024-02-28 08:11:15 -05:00
|
|
|
base_url = await self.config.base_url()
|
|
|
|
api_key = await self.config.api_key()
|
|
|
|
server_id = await self.config.server_id()
|
2024-02-28 08:14:40 -05:00
|
|
|
|
|
|
|
extra_headers = {
|
|
|
|
"Origin": base_url
|
|
|
|
}
|
|
|
|
|
2024-02-27 23:02:03 -05:00
|
|
|
try:
|
|
|
|
client = PterodactylClient(base_url, api_key).client
|
|
|
|
websocket_credentials = client.servers.get_websocket(server_id)
|
2024-02-28 08:37:02 -05:00
|
|
|
self.logger.debug("Websocket connection details retrieved:\nSocket: %s\nToken: %s", websocket_credentials['data']['socket'], websocket_credentials['data']['token'])
|
2024-02-27 23:02:03 -05:00
|
|
|
except exceptions.ClientConfigError as e:
|
|
|
|
self.logger.error(f'Failed to initialize Pterodactyl client: {e}')
|
|
|
|
return
|
|
|
|
except exceptions.PterodactylApiError as e:
|
|
|
|
self.logger.error(f'Failed to retrieve Pterodactyl websocket: {e}')
|
|
|
|
return
|
|
|
|
|
2024-02-28 08:14:40 -05:00
|
|
|
async with websockets.connect(websocket_credentials['data']['socket'], extra_headers=extra_headers) as websocket:
|
2024-02-27 23:02:03 -05:00
|
|
|
self.logger.debug("WebSocket connection established")
|
|
|
|
|
2024-02-27 23:18:17 -05:00
|
|
|
auth_message = json.dumps({"event": "auth", "args": [websocket_credentials['data']['token']]})
|
2024-02-27 23:02:03 -05:00
|
|
|
await websocket.send(auth_message)
|
|
|
|
self.logger.debug("Authentication message sent")
|
|
|
|
|
|
|
|
self.client = client
|
|
|
|
self.websocket = websocket
|
|
|
|
|
|
|
|
while True:
|
|
|
|
message = await websocket.recv()
|
2024-02-28 08:10:46 -05:00
|
|
|
if json.loads(message)['event'] in ['token expiring', 'token expired']:
|
|
|
|
self.logger.debug("Received token expiring/expired event. Refreshing token.")
|
2024-02-27 23:18:17 -05:00
|
|
|
websocket_credentials = client.servers.get_websocket(server_id)
|
|
|
|
auth_message = json.dumps({"event": "auth", "args": [websocket_credentials['data']['token']]})
|
2024-02-28 08:10:46 -05:00
|
|
|
await websocket.send(auth_message)
|
|
|
|
self.logger.debug("Authentication message sent")
|
|
|
|
if json.loads(message)['event'] == 'auth success':
|
|
|
|
self.logger.debug("Authentication successful")
|
2024-02-27 23:02:03 -05:00
|
|
|
self.logger.debug("Received message: %s", message)
|
|
|
|
|
2024-02-28 08:47:24 -05:00
|
|
|
def get_task(self):
|
|
|
|
return self.bot.loop.create_task(self.establish_websocket_connection(), name="Pterodactyl Websocket Connection")
|
|
|
|
|
2024-02-27 23:02:03 -05:00
|
|
|
async def cog_load(self):
|
2024-02-28 08:47:24 -05:00
|
|
|
self.task = self.get_task()
|
2024-02-27 23:02:03 -05:00
|
|
|
|
|
|
|
async def cog_unload(self):
|
2024-02-28 08:47:24 -05:00
|
|
|
self.task.cancel()
|
2024-02-27 23:02:03 -05:00
|
|
|
await self.client._session.close()
|
2024-02-28 08:11:23 -05:00
|
|
|
|
|
|
|
@commands.group(autohelp = True, name = "pterodactyl", aliases = ["ptero"])
|
|
|
|
async def pterodactyl(self, ctx: commands.Context):
|
|
|
|
"""Pterodactyl allows you to manage your Pterodactyl Panel from Discord."""
|
|
|
|
pass
|
|
|
|
|
|
|
|
@pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"])
|
|
|
|
async def pterodactyl_config(self, ctx: commands.Context):
|
|
|
|
"""Configure Pterodactyl settings."""
|
|
|
|
pass
|
|
|
|
|
|
|
|
@pterodactyl_config.command(name = "url")
|
|
|
|
async def pterodactyl_config_base_url(self, ctx: commands.Context, base_url: str):
|
|
|
|
"""Set the base URL of your Pterodactyl Panel. Please include the protocol (http/https)."""
|
|
|
|
await self.config.base_url.set(base_url)
|
|
|
|
await ctx.send(f"Base URL set to {base_url}")
|
2024-02-28 08:47:24 -05:00
|
|
|
await self.task.cancel()
|
|
|
|
self.task = self.get_task()
|
2024-02-28 08:11:23 -05:00
|
|
|
|
|
|
|
@pterodactyl_config.command(name = "apikey")
|
|
|
|
async def pterodactyl_config_api_key(self, ctx: commands.Context, api_key: str):
|
|
|
|
"""Set the API key for your Pterodactyl Panel."""
|
|
|
|
await self.config.api_key.set(api_key)
|
|
|
|
await ctx.send(f"API key set to `{api_key[:5]}...{api_key[-4:]}`")
|
2024-02-28 08:47:24 -05:00
|
|
|
await self.task.cancel()
|
|
|
|
self.task = self.get_task()
|
2024-02-28 08:11:23 -05:00
|
|
|
|
|
|
|
@pterodactyl_config.command(name = "serverid")
|
|
|
|
async def pterodactyl_config_server_id(self, ctx: commands.Context, server_id: str):
|
|
|
|
"""Set the server ID for your Pterodactyl Panel."""
|
|
|
|
await self.config.server_id.set(server_id)
|
|
|
|
await ctx.send(f"Server ID set to {server_id}")
|
2024-02-28 08:47:24 -05:00
|
|
|
await self.task.cancel()
|
|
|
|
self.task = self.get_task()
|