2022-07-01 14:28:39 +04:00
|
|
|
"""Aternos Minecraft server"""
|
|
|
|
|
2022-01-11 18:08:59 +04:00
|
|
|
import enum
|
2021-10-14 17:56:01 +04:00
|
|
|
import json
|
|
|
|
from requests import Response
|
2022-05-18 18:33:21 +04:00
|
|
|
from typing import Optional, List
|
2021-10-08 19:35:20 +04:00
|
|
|
|
2022-03-18 18:38:36 +04:00
|
|
|
from .atconnect import AternosConnect
|
2022-07-01 10:31:23 +04:00
|
|
|
from .aterrors import ServerStartError
|
2022-03-18 18:38:36 +04:00
|
|
|
from .atfm import FileManager
|
|
|
|
from .atconf import AternosConfig
|
|
|
|
from .atplayers import PlayersList
|
2022-06-16 15:40:10 +04:00
|
|
|
from .atplayers import Lists
|
2022-01-22 15:10:30 +04:00
|
|
|
from .atwss import AternosWss
|
2021-10-15 15:12:45 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
|
2022-03-18 18:38:36 +04:00
|
|
|
class Edition(enum.IntEnum):
|
2022-06-16 15:40:10 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
"""Server edition type enum"""
|
|
|
|
|
|
|
|
java = 0
|
|
|
|
bedrock = 1
|
2022-06-16 15:40:10 +04:00
|
|
|
|
2021-10-15 15:12:45 +04:00
|
|
|
|
2022-01-11 18:08:59 +04:00
|
|
|
class Status(enum.IntEnum):
|
2022-06-16 15:40:10 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
"""Server numeric status enum.
|
|
|
|
It is highly recommended to use
|
|
|
|
`AternosServer.status` instead of
|
|
|
|
`AternosServer.status_num`"""
|
|
|
|
|
|
|
|
off = 0
|
|
|
|
on = 1
|
|
|
|
starting = 2
|
|
|
|
shutdown = 3
|
|
|
|
unknown = 6
|
|
|
|
error = 7
|
|
|
|
confirm = 10
|
2022-06-16 15:40:10 +04:00
|
|
|
|
2021-10-08 19:35:20 +04:00
|
|
|
|
|
|
|
class AternosServer:
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
"""Class for controlling your Aternos Minecraft server
|
|
|
|
|
|
|
|
:param servid: Unique server IDentifier
|
|
|
|
:type servid: str
|
|
|
|
:param atconn: :class:`python_aternos.atconnect.AternosConnect`
|
|
|
|
instance with initialized Aternos session
|
|
|
|
:type atconn: python_aternos.atconnect.AternosConnect
|
|
|
|
:param reqinfo: Automatically call AternosServer.fetch()
|
|
|
|
to get all info, defaults to `True`
|
|
|
|
:type reqinfo: bool, optional
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self, servid: str,
|
|
|
|
atconn: AternosConnect,
|
|
|
|
reqinfo: bool = True) -> None:
|
|
|
|
|
|
|
|
self.servid = servid
|
|
|
|
self.atconn = atconn
|
|
|
|
if reqinfo:
|
|
|
|
self.fetch()
|
|
|
|
|
|
|
|
def fetch(self) -> None:
|
|
|
|
|
|
|
|
"""Send a request to Aternos API to get all server info"""
|
|
|
|
|
|
|
|
servreq = self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/status.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
self._info = json.loads(servreq.content)
|
|
|
|
|
|
|
|
def wss(self, autoconfirm: bool = False) -> AternosWss:
|
|
|
|
|
|
|
|
"""Returns :class:`python_aternos.atwss.AternosWss`
|
|
|
|
instance for listening server streams in real-time
|
|
|
|
|
|
|
|
:param autoconfirm: Automatically start server status listener
|
|
|
|
when AternosWss connects to API to confirm
|
|
|
|
server launching, defaults to `False`
|
|
|
|
:type autoconfirm: bool, optional
|
|
|
|
:return: :class:`python_aternos.atwss.AternosWss` object
|
|
|
|
:rtype: python_aternos.atwss.AternosWss
|
|
|
|
"""
|
|
|
|
|
|
|
|
return AternosWss(self, autoconfirm)
|
|
|
|
|
2022-07-01 14:28:39 +04:00
|
|
|
def start(
|
|
|
|
self,
|
|
|
|
headstart: bool = False,
|
|
|
|
accepteula: bool = True) -> None:
|
2022-06-23 15:13:56 +04:00
|
|
|
|
|
|
|
"""Starts a server
|
|
|
|
|
|
|
|
:param headstart: Start a server in the headstart mode
|
|
|
|
which allows you to skip all queue, defaults to `False`
|
|
|
|
:type headstart: bool, optional
|
|
|
|
:param accepteula: Automatically accept
|
|
|
|
the Mojang EULA, defaults to `True`
|
|
|
|
:type accepteula: bool, optional
|
2022-07-01 10:31:23 +04:00
|
|
|
:raises ServerStartError: When Aternos
|
|
|
|
is unable to start the server
|
2022-06-23 15:13:56 +04:00
|
|
|
"""
|
|
|
|
|
|
|
|
startreq = self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/start.php',
|
|
|
|
'GET', params={'headstart': int(headstart)},
|
|
|
|
sendtoken=True
|
|
|
|
)
|
|
|
|
startresult = startreq.json()
|
2022-06-16 15:40:10 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
if startresult['success']:
|
|
|
|
return
|
2022-07-01 10:31:23 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
error = startresult['error']
|
2021-10-08 19:35:20 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
if error == 'eula' and accepteula:
|
|
|
|
self.eula()
|
2022-07-01 14:28:39 +04:00
|
|
|
self.start(accepteula=False)
|
|
|
|
return
|
2022-07-01 10:31:23 +04:00
|
|
|
|
|
|
|
raise ServerStartError(error)
|
2022-01-11 18:08:59 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
def confirm(self) -> None:
|
2021-10-08 19:35:20 +04:00
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
"""Confirms server launching"""
|
|
|
|
|
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/confirm.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
def stop(self) -> None:
|
|
|
|
|
|
|
|
"""Stops the server"""
|
|
|
|
|
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/stop.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
def cancel(self) -> None:
|
|
|
|
|
|
|
|
"""Cancels server launching"""
|
|
|
|
|
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/cancel.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
def restart(self) -> None:
|
|
|
|
|
|
|
|
"""Restarts the server"""
|
|
|
|
|
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/restart.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
def eula(self) -> None:
|
|
|
|
|
|
|
|
"""Accepts the Mojang EULA"""
|
|
|
|
|
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/eula.php',
|
|
|
|
'GET', sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
def files(self) -> FileManager:
|
|
|
|
|
|
|
|
"""Returns :class:`python_aternos.atfm.FileManager`
|
|
|
|
instance for file operations
|
|
|
|
|
|
|
|
:return: :class:`python_aternos.atfm.FileManager` object
|
|
|
|
:rtype: python_aternos.atfm.FileManager
|
|
|
|
"""
|
|
|
|
|
|
|
|
return FileManager(self)
|
|
|
|
|
|
|
|
def config(self) -> AternosConfig:
|
|
|
|
|
|
|
|
"""Returns :class:`python_aternos.atconf.AternosConfig`
|
|
|
|
instance for editing server settings
|
|
|
|
|
|
|
|
:return: :class:`python_aternos.atconf.AternosConfig` object
|
|
|
|
:rtype: python_aternos.atconf.AternosConfig
|
|
|
|
"""
|
|
|
|
|
|
|
|
return AternosConfig(self)
|
|
|
|
|
|
|
|
def players(self, lst: Lists) -> PlayersList:
|
|
|
|
|
|
|
|
"""Returns :class:`python_aternos.atplayers.PlayersList`
|
|
|
|
instance for managing operators, whitelist and banned players lists
|
|
|
|
|
|
|
|
:param lst: Players list type, must be
|
|
|
|
the :class:`python_aternos.atplayers.Lists` enum value
|
|
|
|
:type lst: python_aternos.atplayers.Lists
|
|
|
|
:return: :class:`python_aternos.atplayers.PlayersList`
|
|
|
|
:rtype: python_aternos.atplayers.PlayersList
|
|
|
|
"""
|
|
|
|
|
|
|
|
return PlayersList(lst, self)
|
|
|
|
|
|
|
|
def atserver_request(
|
|
|
|
self, url: str, method: str,
|
|
|
|
params: Optional[dict] = None,
|
|
|
|
data: Optional[dict] = None,
|
|
|
|
headers: Optional[dict] = None,
|
|
|
|
sendtoken: bool = False) -> Response:
|
|
|
|
|
|
|
|
"""Sends a request to Aternos API
|
|
|
|
with server IDenitfier parameter
|
|
|
|
|
|
|
|
:param url: Request URL
|
|
|
|
:type url: str
|
|
|
|
:param method: Request method, must be GET or POST
|
|
|
|
:type method: str
|
|
|
|
:param params: URL parameters, defaults to None
|
|
|
|
:type params: Optional[dict], optional
|
|
|
|
:param data: POST request data, if the method is GET,
|
|
|
|
this dict will be combined with params, defaults to None
|
|
|
|
:type data: Optional[dict], optional
|
|
|
|
:param headers: Custom headers, defaults to None
|
|
|
|
:type headers: Optional[dict], optional
|
|
|
|
:param sendtoken: If the ajax and SEC token
|
|
|
|
should be sent, defaults to False
|
|
|
|
:type sendtoken: bool, optional
|
|
|
|
:return: API response
|
|
|
|
:rtype: requests.Response
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self.atconn.request_cloudflare(
|
|
|
|
url=url, method=method,
|
|
|
|
params=params, data=data,
|
|
|
|
headers=headers,
|
|
|
|
reqcookies={
|
|
|
|
'ATERNOS_SERVER': self.servid
|
|
|
|
},
|
|
|
|
sendtoken=sendtoken
|
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def subdomain(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server subdomain (part of domain before `.aternos.me`)
|
|
|
|
|
|
|
|
:return: Subdomain
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
atdomain = self.domain
|
|
|
|
return atdomain[:atdomain.find('.')]
|
|
|
|
|
|
|
|
@subdomain.setter
|
|
|
|
def subdomain(self, value: str) -> None:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Set new subdomain for your server
|
|
|
|
|
|
|
|
:param value: Subdomain
|
|
|
|
:type value: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/options/subdomain.php',
|
|
|
|
'GET', params={'subdomain': value},
|
|
|
|
sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def motd(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server message of the day,
|
|
|
|
which is shown below its name in the servers list
|
|
|
|
|
|
|
|
:return: MOTD
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['motd']
|
|
|
|
|
|
|
|
@motd.setter
|
|
|
|
def motd(self, value: str) -> None:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Set new message of the day
|
|
|
|
|
|
|
|
:param value: MOTD
|
|
|
|
:type value: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
self.atserver_request(
|
|
|
|
'https://aternos.org/panel/ajax/options/motd.php',
|
|
|
|
'POST', data={'motd': value},
|
|
|
|
sendtoken=True
|
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def address(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Full server address including domain and port
|
|
|
|
|
|
|
|
:return: Server address
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['displayAddress']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def domain(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server domain (test.aternos.me),
|
|
|
|
address without port number
|
|
|
|
|
|
|
|
:return: Domain
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['ip']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def port(self) -> int:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server port number
|
|
|
|
|
|
|
|
:return: Port
|
|
|
|
:rtype: int
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['port']
|
|
|
|
|
|
|
|
@property
|
2022-07-01 14:28:39 +04:00
|
|
|
def edition(self) -> Edition:
|
|
|
|
|
|
|
|
"""Server software edition: Java or Bedrock
|
|
|
|
|
|
|
|
:return: Software edition
|
|
|
|
:rtype: Edition
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
soft_type = self._info['bedrock']
|
2022-07-01 14:28:39 +04:00
|
|
|
return Edition(soft_type)
|
2022-06-23 15:13:56 +04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def software(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server software name (e.g. `Vanilla`)
|
|
|
|
|
|
|
|
:return: Software name
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['software']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def version(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server software version (e.g. `1.16.5`)
|
|
|
|
|
|
|
|
:return: Software version
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['version']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def status(self) -> str:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server status string (offline, loading)
|
|
|
|
|
|
|
|
:return: Status string
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['class']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def status_num(self) -> int:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server numeric status. It is highly recommended
|
|
|
|
to use status string instead of a number.
|
|
|
|
|
|
|
|
:return: Status code
|
|
|
|
:rtype: Status
|
|
|
|
"""
|
|
|
|
|
|
|
|
return Status(self._info['status'])
|
2022-06-23 15:13:56 +04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def players_list(self) -> List[str]:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""List of connected players nicknames
|
|
|
|
|
|
|
|
:return: Connected players
|
|
|
|
:rtype: List[str]
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return self._info['playerlist']
|
|
|
|
|
|
|
|
@property
|
|
|
|
def players_count(self) -> int:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""How many connected players
|
|
|
|
|
|
|
|
:return: Connected players count
|
|
|
|
:rtype: int
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return int(self._info['players'])
|
|
|
|
|
|
|
|
@property
|
|
|
|
def slots(self) -> int:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server slots, how many players can connect
|
|
|
|
|
|
|
|
:return: Slots count
|
|
|
|
:rtype: int
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return int(self._info['slots'])
|
|
|
|
|
|
|
|
@property
|
|
|
|
def ram(self) -> int:
|
2022-07-01 14:28:39 +04:00
|
|
|
|
|
|
|
"""Server used RAM in MB
|
|
|
|
|
|
|
|
:return: Used RAM
|
|
|
|
:rtype: int
|
|
|
|
"""
|
|
|
|
|
2022-06-23 15:13:56 +04:00
|
|
|
return int(self._info['ram'])
|