WebSocket, code improvements, API update

This commit is contained in:
DarkCat09 2022-01-11 18:08:59 +04:00
parent ca9cda3b51
commit 6993aadf03
9 changed files with 284 additions and 170 deletions

View file

@ -1,4 +1,6 @@
Client - C, Server - S. Client - C, Server - S.
Note: "stream"/"type" means the type of received data:
a new console line, an updated RAM or TPS value...
C> C>
GET wss://aternos.org/hermes/ GET wss://aternos.org/hermes/
@ -29,11 +31,10 @@ C> {"stream":"console","type":"command","data":"list"}
S> {"stream":"console","type":"line","data":"list\r"} S> {"stream":"console","type":"line","data":"list\r"}
S> {"stream":"console","type":"line","data":"[23:28:28] [Server thread/INFO] [minecraft/DedicatedServer]: There are §r0§r/§r8§r players online:§r\r"} S> {"stream":"console","type":"line","data":"[23:28:28] [Server thread/INFO] [minecraft/DedicatedServer]: There are §r0§r/§r8§r players online:§r\r"}
S> {"stream":"console","type":"line","data":"[23:28:28] [Server thread/INFO] [minecraft/DedicatedServer]: \r"} S> {"stream":"console","type":"line","data":"[23:28:28] [Server thread/INFO] [minecraft/DedicatedServer]: \r"}
# AdBlock detected # ???
C> {"type":"❤"} C> {"type":"❤"}
*** Page was refreshed *** Page was refreshed
(What's the difference between stream:heap and stream:console?)
C> C>
GET wss://aternos.org/hermes/ GET wss://aternos.org/hermes/
@ -69,5 +70,32 @@ S> {"type":"status","message":"{\"brand\":\"aternos\",\"status\":5,\"change\":16
S> {"type":"status","message":"{\"brand\":\"aternos\",\"status\":0,\"change\":1640978991,\"slots\":8,\"problems\":0,\"players\":0,\"playerlist\":[],\"message\":{\"text\":\"\",\"class\":\"blue\"},\"dynip\":null,\"bedrock\":false,\"host\":\"\",\"port\":61370,\"headstarts\":null,\"ram\":0,\"lang\":\"offline\",\"label\":\"\\u041e\\u0444\\u0444\\u043b\\u0430\\u0439\\u043d\",\"class\":\"offline\",\"countdown\":null,\"queue\":null,\"id\":\"cDRCfaQjQDaABPKL\",\"name\":\"inc09\",\"software\":\"Forge\",\"softwareId\":\"p71sAEKNbhea4UEm\",\"type\":\"forge\",\"version\":\"1.12.2 (14.23.5.2860)\",\"deprecated\":false,\"ip\":\"inc09.aternos.me\",\"displayAddress\":\"inc09.aternos.me:61370\",\"motd\":\"IndustrialCraft 2\",\"icon\":\"fa-stop-circle\",\"dns\":{\"type\":\"DEFAULT\",\"domains\":[\"inc09.aternos.me\"],\"host\":null,\"port\":null}}"} S> {"type":"status","message":"{\"brand\":\"aternos\",\"status\":0,\"change\":1640978991,\"slots\":8,\"problems\":0,\"players\":0,\"playerlist\":[],\"message\":{\"text\":\"\",\"class\":\"blue\"},\"dynip\":null,\"bedrock\":false,\"host\":\"\",\"port\":61370,\"headstarts\":null,\"ram\":0,\"lang\":\"offline\",\"label\":\"\\u041e\\u0444\\u0444\\u043b\\u0430\\u0439\\u043d\",\"class\":\"offline\",\"countdown\":null,\"queue\":null,\"id\":\"cDRCfaQjQDaABPKL\",\"name\":\"inc09\",\"software\":\"Forge\",\"softwareId\":\"p71sAEKNbhea4UEm\",\"type\":\"forge\",\"version\":\"1.12.2 (14.23.5.2860)\",\"deprecated\":false,\"ip\":\"inc09.aternos.me\",\"displayAddress\":\"inc09.aternos.me:61370\",\"motd\":\"IndustrialCraft 2\",\"icon\":\"fa-stop-circle\",\"dns\":{\"type\":\"DEFAULT\",\"domains\":[\"inc09.aternos.me\"],\"host\":null,\"port\":null}}"}
# Backup (why is this info here?) # Backup (why is this info here?)
S> {"type":"backup_progress","message":"{\"id\":\"\",\"progress\":0,\"action\":\"reset\",\"auto\":false,\"done\":false}"} S> {"type":"backup_progress","message":"{\"id\":\"\",\"progress\":0,\"action\":\"reset\",\"auto\":false,\"done\":false}"}
# AdBlock detected # ???
C> {"type":"❤"} C> {"type":"❤"}
*** Queue example
S> {"type":"queue_reduced","message":"{\"queue\":0,\"total\":49,\"maxtime\":3}"}
S> {"type":"queue_reduced","message":"{\"queue\":0,\"total\":49,\"maxtime\":2}"}
# From server.js:
# var percentage = lastStatus.queue.position / queue.total * 100;
if (queue.maxtime) {
let minutes = Math.round((queue.maxtime - ((Date.now() / 1000) - lastStatus.queue.jointime)) / 60);
if (minutes < 1 || lastStatus.queue.pending === "ready") {
minutes = 1;
}
if (minutes > lastStatus.queue.minutes) {
minutes = lastStatus.queue.minutes;
}
if (lastStatus.queue.minutes - minutes <= 3) {
lastStatus.queue.minutes = minutes;
}
lastStatus.queue.time = "ca. " + lastStatus.queue.minutes + " min";
}
*** type=tick
S> {"stream":"tick","type":"tick","data":{"averageTickTime":8.526042}}
S> {"stream":"tick","type":"tick","data":{"averageTickTime":1.4948028}}
# From legilimens.js:
# let tps = Math.round(Math.min(1000 / data.averageTickTime, 20) * 10) / 10;

View file

@ -5,7 +5,8 @@ from typing import Optional, Union, List
from . import atserver from . import atserver
from . import atconnect from . import atconnect
from . import aterrors from . import aterrors
from . import client_secrets
from .aterrors import AternosCredentialsError
class Client: class Client:
@ -13,48 +14,58 @@ class Client:
self.atconn = atconn self.atconn = atconn
# if google:
# flow = Flow.from_client_config\
# (
# json.loads(
# base64.standard_base64decode(client_secrets.CSJSON)
# ),
# scopes=['openid', 'email']
# )
# # localhost:8764
# flow.run_local_server(port=8764, open_browser=False)
@classmethod @classmethod
def from_hashed(cls, username:str, md5:str): def from_hashed(cls, username:str, md5:str):
atconn = atconnect.AternosConnect() atconn = atconnect.AternosConnect()
token = atconn.parse_token() atconn.parse_token()
sec = atconn.generate_sec() atconn.generate_sec()
loginreq = self.atconn.request_cloudflare( credentials = {
'user': username,
'password': md5
}
loginreq = atconn.request_cloudflare(
f'https://aternos.org/panel/ajax/account/login.php', f'https://aternos.org/panel/ajax/account/login.php',
atconnect.REQPOST, data=self.credentials, atconnect.REQPOST, data=credentials,
sendtoken=True sendtoken=True
) )
if loginreq.cookies.get('ATERNOS_SESSION', None) == None: if loginreq.cookies.get('ATERNOS_SESSION', None) == None:
raise aterrors.AternosCredentialsError( raise AternosCredentialsError(
'Check your username and password' 'Check your username and password'
) )
cls(atconn) return cls(atconn)
@classmethod @classmethod
def from_credentials(cls, username:str, password:str): def from_credentials(cls, username:str, password:str):
cls.from_hashed(
username, pswd_bytes = password.encode('utf-8')
hashlib.md5(password.encode('utf-8'))\ md5 = hashlib.md5(pswd_bytes).hexdigest().lower()
.hexdigest().lower()
) return cls.from_hashed(username, md5)
@classmethod @classmethod
def with_google(cls): def from_session(cls, session:str):
pass
atconn = atconnect.AternosConnect()
atconn.session.cookies.set('ATERNOS_SESSION', session)
atconn.parse_token()
atconn.generate_sec()
return cls(atconn)
@staticmethod
def google() -> str:
atconn = atconnect.AternosConnect()
auth = atconn.request_cloudflare(
'https://aternos.org/auth/google-login',
atconnect.REQGET, redirect=False
)
return auth.headers['Location']
@property @property
def servers(self) -> List[atserver.AternosServer]: def servers(self) -> List[atserver.AternosServer]:

View file

@ -1,3 +1,4 @@
import enum
import re import re
import lxml.html import lxml.html
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
@ -8,68 +9,75 @@ from . import atconnect
if TYPE_CHECKING: if TYPE_CHECKING:
from atserver import AternosServer from atserver import AternosServer
OPT_PLAYERS = 'max-players' class ServerOpts(enum.Enum):
OPT_GAMEMODE = 'gamemode' players = 'max-players'
OPT_DIFFICULTY = 'difficulty' gm = 'gamemode'
OPT_WHITELIST = 'white-list' difficulty = 'difficulty'
OPT_ONLINE = 'online-mode' whl = 'white-list'
OPT_PVP = 'pvp' online = 'online-mode'
OPT_CMDBLOCK = 'enable-command-block' pvp = 'pvp'
OPT_FLIGHT = 'allow-flight' cmdblock = 'enable-command-block'
OPT_ANIMALS = 'spawn-animals' flight = 'allow-flight'
OPT_MONSTERS = 'spawn-monsters' animals = 'spawn-animals'
OPT_VILLAGERS = 'spawn-npcs' monsters = 'spawn-monsters'
OPT_NETHER = 'allow-nether' villagers = 'spawn-npcs'
OPT_FORCEGM = 'force-gamemode' nether = 'allow-nether'
OPT_SPAWNLOCK = 'spawn-protection' forcegm = 'force-gamemode'
OPT_CHEATS = 'allow-cheats' spawnlock = 'spawn-protection'
OPT_RESOURCEPACK = 'resource-pack' cmds = 'allow-cheats'
pack = 'resource-pack'
DAT_PREFIX = 'Data:' DAT_PREFIX = 'Data:'
DAT_SEED = 'RandomSeed'
DAT_HARDCORE = 'hardcore' class WorldOpts(enum.Enum):
DAT_DIFFICULTY = 'Difficulty' seed = 'randomseed'
hardcore = 'hardcore'
difficulty = 'difficulty'
DAT_GR_PREFIX = 'Data:GameRules:' DAT_GR_PREFIX = 'Data:GameRules:'
DAT_GR_ADVS = 'announceAdvancements'
DAT_GR_CMDOUT = 'commandBlockOutput' class WorldRules(enum.Enum):
DAT_GR_ELYTRA = 'disableElytraMovementCheck' advs = 'announceadvancements'
DAT_GR_DAYLIGHT = 'doDaylightCycle' cmdout = 'commandblockoutput'
DAT_GR_ENTDROPS = 'doEntityDrops' elytra = 'disableelytramovementcheck'
DAT_GR_FIRETICK = 'doFireTick' daynight = 'dodaylightcycle'
DAT_GR_LIMITCRAFT = 'doLimitedCrafting' entdrop = 'doentitydrops'
DAT_GR_MOBLOOT = 'doMobLoot' fire = 'dofiretick'
DAT_GR_MOBS = 'doMobSpawning' limitcraft = 'dolimitedcrafting'
DAT_GR_TILEDROPS = 'doTileDrops' mobloot = 'domobloot'
DAT_GR_WEATHER = 'doWeatherCycle' mobs = 'domobspawning'
DAT_GR_KEEPINV = 'keepInventory' blockdrop = 'dotiledrops'
DAT_GR_DEATHMSG = 'showDeathMessages' weather = 'doweathercycle'
DAT_GR_ADMINCMDLOG = 'logAdminCommands' keepinv = 'keepinventory'
DAT_GR_CMDLEN = 'maxCommandChainLength' deathmsg = 'showdeathmessages'
DAT_GR_ENTCRAM = 'maxEntityCramming' admincmdlog = 'logadmincommands'
DAT_GR_MOBGRIEF = 'mobGriefing' cmdlen = 'maxcommandchainlength'
DAT_GR_REGEN = 'naturalRegeneration' entcram = 'maxentitycramming'
DAT_GR_RNDTICK = 'randomTickSpeed' mobgrief = 'mobgriefing'
DAT_GR_SPAWNRADIUS = 'spawnRadius' regen = 'naturalregeneration'
DAT_GR_REDUCEDF3 = 'reducedDebugInfo' rndtick = 'randomtickspeed'
DAT_GR_SPECTCHUNK = 'spectatorsGenerateChunks' spawnradius = 'spawnradius'
DAT_GR_CMDFB = 'sendCommandFeedback' reducedf3 = 'reduceddebuginfo'
spectchunkgen = 'spectatorsgeneratechunks'
cmdfb = 'sendcommandfeedback'
DAT_TYPE_WORLD = 0 DAT_TYPE_WORLD = 0
DAT_TYPE_GR = 1 DAT_TYPE_GR = 1
GM_SURVIVAL = 0 class Gamemode(enum.IntEnum):
GM_CREATIVE = 1 survival = 0
GM_ADVENTURE = 2 creative = 1
GM_SPECTATOR = 3 adventure = 2
spectator = 3
DF_PEACEFUL = 0 class Difficulty(enum.IntEnum):
DF_EASY = 1 peaceful = 0
DF_NORMAL = 2 easy = 1
DF_HARD = 3 normal = 2
hard = 3
JAVA_JDK = 'openjdk:{}' JDK = 'openjdk:{}'
JAVA_OPENJ9 = 'adoptopenjdk:{}-jre-openj9-bionic' OJ9 = 'adoptopenjdk:{}-jre-openj9-bionic'
FLAG_PROP_TYPE = 1 FLAG_PROP_TYPE = 1
@ -81,6 +89,7 @@ class AternosConfig:
@property @property
def timezone(self) -> str: def timezone(self) -> str:
optreq = self.atserv.atserver_request( optreq = self.atserv.atserver_request(
'https://aternos.org/options', 'https://aternos.org/options',
atconnect.REQGET atconnect.REQGET
@ -93,6 +102,7 @@ class AternosConfig:
@timezone.setter @timezone.setter
def timezone(self, value:str) -> None: def timezone(self, value:str) -> None:
matches_tz = re.search(r'(?:^[A-Z]\w+\/[A-Z]\w+$)|^UTC$', value) matches_tz = re.search(r'(?:^[A-Z]\w+\/[A-Z]\w+$)|^UTC$', value)
if matches_tz == None: if matches_tz == None:
raise AttributeError('Timezone must match zoneinfo format: Area/Location') raise AttributeError('Timezone must match zoneinfo format: Area/Location')
@ -105,6 +115,7 @@ class AternosConfig:
@property @property
def java_version(self) -> str: def java_version(self) -> str:
optreq = self.atserv.atserver_request( optreq = self.atserv.atserver_request(
'https://aternos.org/options', 'https://aternos.org/options',
atconnect.REQGET atconnect.REQGET
@ -117,9 +128,9 @@ class AternosConfig:
@java_version.setter @java_version.setter
def java_version(self, value:str) -> None: def java_version(self, value:str) -> None:
matches_jdkver = re.search(r'^(?:adopt)*openjdk:(\d+)(?:-jre-openj9-bionic)*$', value) matches_jdkver = re.search(r'^(?:adopt)?openjdk:(\d+)(?:-jre-openj9-bionic)?$', value)
if matches_jdkver == None: if matches_jdkver == None:
raise AttributeError('Java image version must match "[adopt]openjdk:%d[-jre-openj9-bionic]" format') raise AttributeError('Incorrect Java image version format!')
self.atserv.atserver_request( self.atserv.atserver_request(
'https://aternos.org/panel/ajax/image.php', 'https://aternos.org/panel/ajax/image.php',
@ -149,6 +160,7 @@ class AternosConfig:
def set_world_prop( def set_world_prop(
self, option:str, value:Any, self, option:str, value:Any,
proptype:int, world:str='world') -> None: proptype:int, world:str='world') -> None:
prefix = DAT_PREFIX prefix = DAT_PREFIX
if proptype == DAT_TYPE_GR: if proptype == DAT_TYPE_GR:
prefix = DAT_GR_PREFIX prefix = DAT_GR_PREFIX
@ -162,6 +174,7 @@ class AternosConfig:
def get_world_props( def get_world_props(
self, world:str='world', self, world:str='world',
flags:int=FLAG_PROP_TYPE) -> Dict[str,Any]: flags:int=FLAG_PROP_TYPE) -> Dict[str,Any]:
self.__get_all_props( self.__get_all_props(
f'https://aternos.org/files/{world}/level.dat', f'https://aternos.org/files/{world}/level.dat',
flags, [DAT_PREFIX, DAT_GR_PREFIX] flags, [DAT_PREFIX, DAT_GR_PREFIX]

View file

@ -36,6 +36,8 @@ class AternosConnect:
js_code = re.findall(r'\(\(\)(.*?)\)\(\);', text) js_code = re.findall(r'\(\(\)(.*?)\)\(\);', text)
token_func = js_code[1] if len(js_code) > 1 else js_code[0] token_func = js_code[1] if len(js_code) > 1 else js_code[0]
print('*** Function:', token_func)
ctx = atjsparse.exec(token_func) ctx = atjsparse.exec(token_func)
self.token = ctx.window['AJAX_TOKEN'] self.token = ctx.window['AJAX_TOKEN']
@ -64,95 +66,86 @@ class AternosConnect:
for i in range(randlen+1): for i in range(randlen+1):
rand_arr.append('') rand_arr.append('')
rand_alphanum = \ rand = random.random()
self.convert_num(random.random(),36) + \ rand_alphanum = self.convert_num(rand, 36) + ('0' * 17)
'00000000000000000'
return (rand_alphanum[2:18].join(rand_arr)[:randlen])
def convert_num(self, num:Union[int,float], base:int) -> str: return (rand_alphanum[:18].join(rand_arr)[:randlen])
def convert_num(
self, num:Union[int,float,str],
base:int, frombase:int=10) -> str:
if isinstance(num, str):
num = int(num, frombase)
if isinstance(num, float):
sliced = str(num)[2:]
num = int(sliced)
symbols = '0123456789abcdefghijklmnopqrstuvwxyz'
basesym = symbols[:base]
result = '' result = ''
while num > 0: while num > 0:
result = str(num % base) + result rem = num % base
result = str(basesym[rem]) + result
num //= base num //= base
return result return result
def request_cloudflare( def request_cloudflare(
self, url:str, method:int, self, url:str, method:int, retries:int=10,
retries:int=10, params:Optional[dict]=None, data:Optional[dict]=None,
params:Optional[dict]=None, headers:Optional[dict]=None, reqcookies:Optional[dict]=None,
data:Optional[dict]=None, sendtoken:bool=False, redirect:bool=True) -> Response:
headers:Optional[dict]=None,
reqcookies:Optional[dict]=None,
sendtoken:bool=False) -> Response:
cftitle = '<title>Please Wait... | Cloudflare</title>' cftitle = '<title>Please Wait... | Cloudflare</title>'
if sendtoken: if params == None:
url += f'?TOKEN={self.token}&SEC={self.sec}' params = {}
if headers == None: if headers == None:
headers = {} headers = {}
headers['User-Agent'] = REQUA headers['User-Agent'] = REQUA
if sendtoken:
url += f'?TOKEN={self.token}&SEC={self.sec}'
try: try:
cookies = self.session.cookies cookies = self.session.cookies
except AttributeError: except AttributeError:
cookies = None cookies = None
self.session = CloudScraper()
if cookies != None:
self.session.cookies = cookies
if method == REQPOST:
req = self.session.post(
url,
data=data,
headers=headers,
cookies=reqcookies
)
else:
req = self.session.get(
url,
params=params,
headers=headers,
cookies=reqcookies
)
countdown = retries countdown = retries
while cftitle in req.text \ while True:
and (countdown > 0):
self.session = CloudScraper() self.session = CloudScraper()
if cookies != None: if cookies != None:
self.session.cookies = cookies self.session.cookies = cookies
if reqcookies != None: if reqcookies != None:
for cookiekey in reqcookies: for cookiekey in reqcookies:
self.session.cookies.set(cookiekey, reqcookies[cookiekey]) self.session.cookies.set(cookiekey, reqcookies[cookiekey])
time.sleep(1) time.sleep(1)
if method == REQPOST: if method == REQPOST:
req = self.session.post( req = self.session.post(
url, url, data=data, params=params,
data=data, headers=headers, cookies=reqcookies,
headers=headers, allow_redirects=redirect
cookies=reqcookies
) )
else: else:
req = self.session.get( req = self.session.get(
url, url, params=params,
params=params, headers=headers, cookies=reqcookies,
headers=headers, allow_redirects=redirect
cookies=reqcookies )
if not cftitle in req.text:
break
if not countdown > 0:
raise aterrors.CloudflareError(
'The retries limit has been reached'
) )
countdown -= 1 countdown -= 1
print(sendtoken)
try:
print(self.sec, self.token)
except AttributeError:
pass
print(req.status_code)
print(req.cookies)
print(req.url, '', sep='\n---')
return req return req

View file

@ -1,15 +1,14 @@
class AternosError(Exception): class AternosError(Exception):
pass pass
class AternosCredentialsError(AternosError): class AternosCredentialsError(AternosError):
pass pass
class AternosServerStartError(AternosError): class AternosServerStartError(AternosError):
pass pass
class AternosIOError(AternosError): class AternosIOError(AternosError):
pass
class CloudflareError(AternosError):
pass pass

View file

@ -1,6 +1,8 @@
import enum
import re import re
import json import json
import lxml.html import lxml.html
import websockets
from requests import Response from requests import Response
from typing import Optional, Dict from typing import Optional, Dict
@ -10,26 +12,33 @@ from . import atfm
from . import atconf from . import atconf
from . import atplayers from . import atplayers
SOFTWARE_JAVA = 0 JAVA = 0
SOFTWARE_BEDROCK = 1 BEDROCK = 1
PLAYERS_ALLOWED = 'whitelist' class Lists(enum.Enum):
PLAYERS_OPS = 'ops' whl = 'whitelist'
PLAYERS_BANNED = 'banned-players' ops = 'ops'
PLAYERS_IPS = 'banned-ips' ban = 'banned-players'
ips = 'banned-ips'
STATUS_OFFLINE = 0 class Status(enum.IntEnum):
STATUS_ONLINE = 1 off = 0
STATUS_LOADING = 2 on = 1
STATUS_SHUTDOWN = 3 loading = 2
STATUS_ERROR = 7 shutdown = 3
error = 7
class AternosServer: class AternosServer:
def __init__(self, servid:str, atconn:atconnect.AternosConnect) -> None: def __init__(
self, servid:str,
atconn:atconnect.AternosConnect,
savelog:bool=True) -> None:
self.servid = servid self.servid = servid
self.atconn = atconn self.atconn = atconn
self.savelog = savelog
self.log = []
servreq = self.atserver_request( servreq = self.atserver_request(
'https://aternos.org/server', 'https://aternos.org/server',
@ -43,36 +52,91 @@ class AternosServer:
servtree.head.text_content() servtree.head.text_content()
)[1] )[1]
) )
self._ram = 0
self._tps = 0
self.atconn.parse_token(servreq.content) self.atconn.parse_token(servreq.content)
self.atconn.generate_sec() self.atconn.generate_sec()
def start(self, accepteula:bool=True) -> None: async def wss(self):
session = self.atconn.session.cookies['ATERNOS_SESSION']
headers = [
('User-Agent', atconnect.REQUA),
('Cookie',
f'ATERNOS_SESSION={session}; ' + \
f'ATERNOS_SERVER={self.servid}')
]
async with websockets.connect(
'wss://aternos.org/hermes',
extra_headers=headers
) as websocket:
while True:
msg = await websocket.recv()
r = json.loads(msg)
if r['type'] == 'line' \
and r['stream'] == 'console'\
and self.savelog:
self.log.append(r['data'])
if r['type'] == 'heap':
self._ram = r['data']['usage']
if r['type'] == 'tick':
aver = 1000 / r['data']['averageTickTime']
self._tps = 20 if aver > 20 else aver
if r['type'] == 'status':
self._info = json.loads(r['message'])
def start(self, headstart:bool=False, accepteula:bool=True) -> None:
startreq = self.atserver_request( startreq = self.atserver_request(
'https://aternos.org/panel/ajax/start.php', 'https://aternos.org/panel/ajax/start.php',
atconnect.REQGET, sendtoken=True atconnect.REQGET, params={'headstart': int(headstart)},
sendtoken=True
) )
startresult = startreq.json() startresult = startreq.json()
if startresult['success']: if startresult['success']:
return return
error = startresult['error'] error = startresult['error']
if error == 'eula' and accepteula: if error == 'eula' and accepteula:
self.eula() self.eula()
self.start(accepteula=False) self.start(accepteula=False)
elif error == 'eula': elif error == 'eula':
raise aterrors.AternosServerStartError( raise aterrors.AternosServerStartError(
'EULA was not accepted. Use start(accepteula=True)' 'EULA was not accepted. Use start(accepteula=True)'
) )
elif error == 'already': elif error == 'already':
raise aterrors.AternosServerStartError( raise aterrors.AternosServerStartError(
'Server is already running' 'Server is already running'
) )
elif error == 'wrongversion':
raise aterrors.AternosServerStartError(
'Incorrect software version installed'
)
elif error == 'file':
raise aterrors.AternosServerStartError(
'File server is unavailbale, view status.aternos.gmbh'
)
elif error == 'size':
raise aterrors.AternosServerStartError(
f'Available storage size is 4GB, ' + \
f'your server used: {startresult["size"]}'
)
else: else:
raise aterrors.AternosServerStartError( raise aterrors.AternosServerStartError(
f'Unable to start server. Code: {error}' f'Unable to start server, code: {error}'
) )
def confirm(self) -> None: def confirm(self) -> None:
@ -120,6 +184,14 @@ class AternosServer:
def players(self, lst:str) -> atplayers.AternosPlayersList: def players(self, lst:str) -> atplayers.AternosPlayersList:
correct = False
for lsttype in Lists:
if lsttype.value == lst:
correct = True
if not correct:
raise AttributeError('Incorrect players list type! Use Lists enum')
return atplayers.AternosPlayersList(lst, self) return atplayers.AternosPlayersList(lst, self)
def atserver_request( def atserver_request(
@ -129,7 +201,6 @@ class AternosServer:
headers:Optional[dict]=None, headers:Optional[dict]=None,
sendtoken:bool=False) -> Response: sendtoken:bool=False) -> Response:
print(sendtoken)
return self.atconn.request_cloudflare( return self.atconn.request_cloudflare(
url=url, method=method, url=url, method=method,
params=params, data=data, params=params, data=data,
@ -149,7 +220,8 @@ class AternosServer:
def subdomain(self, value:str) -> None: def subdomain(self, value:str) -> None:
self.atserver_request( self.atserver_request(
'https://aternos.org/panel/ajax/options/subdomain.php', 'https://aternos.org/panel/ajax/options/subdomain.php',
atconnect.REQGET, params={'subdomain': value} atconnect.REQGET, params={'subdomain': value},
sendtoken=True
) )
@property @property
@ -179,10 +251,7 @@ class AternosServer:
@property @property
def edition(self) -> int: def edition(self) -> int:
soft_type = self._info['bedrock'] soft_type = self._info['bedrock']
if soft_type == True: return int(soft_type)
return SOFTWARE_BEDROCK
else:
return SOFTWARE_JAVA
@property @property
def software(self) -> str: def software(self) -> str:
@ -198,4 +267,4 @@ class AternosServer:
@property @property
def ram(self) -> int: def ram(self) -> int:
return int(self._info['ram']) return self._ram

View file

@ -1 +0,0 @@
CSJSON = 'eyJpbnN0YWxsZWQiOnsiY2xpZW50X2lkIjoiNjU4MTQyNjkxNjQxLXFnZ21sdGNmdXY0a2I1a2NwczdoZjBiaGlvN2Q0dnUzLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwicHJvamVjdF9pZCI6InB5dGhvbi1hdGVybm9zIiwiYXV0aF91cmkiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvYXV0aCIsInRva2VuX3VyaSI6Imh0dHBzOi8vb2F1dGgyLmdvb2dsZWFwaXMuY29tL3Rva2VuIiwiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwiY2xpZW50X3NlY3JldCI6IkdPQ1NQWC1XUUJsMjIzOTZxcHVLMDJIVXVpWUhhUXNmbC03IiwicmVkaXJlY3RfdXJpcyI6WyJ1cm46aWV0Zjp3ZzpvYXV0aDoyLjA6b29iIiwiaHR0cDovL2xvY2FsaG9zdCJdfX0='

View file

@ -1,4 +1,5 @@
lxml==4.6.2 lxml==4.6.2
requests==2.25.1 requests==2.25.1
cloudscraper==1.2.58 cloudscraper==1.2.58
Js2Py==0.71 js2py==0.71
websockets==10.1

View file

@ -3,9 +3,14 @@ import setuptools
with open('README.md', 'rt') as readme: with open('README.md', 'rt') as readme:
long_description = readme.read() long_description = readme.read()
with open('requirements.txt', 'rt') as f:
requires = f.readlines()
for i, r in enumerate(requires):
requires[i] = r.strip('\r\n')
setuptools.setup( setuptools.setup(
name='python-aternos', name='python-aternos',
version='0.5', version='0.6',
author='Chechkenev Andrey (@DarkCat09)', author='Chechkenev Andrey (@DarkCat09)',
author_email='aacd0709@mail.ru', author_email='aacd0709@mail.ru',
description='An unofficial Aternos API', description='An unofficial Aternos API',
@ -21,11 +26,7 @@ setuptools.setup(
'License :: OSI Approved :: Apache Software License', 'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent' 'Operating System :: OS Independent'
], ],
install_requires=[ install_requires=requires,
'lxml==4.6.2',
'requests==2.25.1',
'cloudscraper==1.2.58'
],
packages=['python_aternos'], packages=['python_aternos'],
python_requires=">=3.6", python_requires=">=3.6",
) )