WebSocket, code improvements, API update
This commit is contained in:
parent
ca9cda3b51
commit
6993aadf03
9 changed files with 284 additions and 170 deletions
|
@ -1,4 +1,6 @@
|
|||
Client - C, Server - S.
|
||||
Note: "stream"/"type" means the type of received data:
|
||||
a new console line, an updated RAM or TPS value...
|
||||
|
||||
C>
|
||||
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":"[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"}
|
||||
# AdBlock detected
|
||||
# ???
|
||||
C> {"type":"❤"}
|
||||
|
||||
*** Page was refreshed
|
||||
(What's the difference between stream:heap and stream:console?)
|
||||
|
||||
C>
|
||||
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}}"}
|
||||
# Backup (why is this info here?)
|
||||
S> {"type":"backup_progress","message":"{\"id\":\"\",\"progress\":0,\"action\":\"reset\",\"auto\":false,\"done\":false}"}
|
||||
# AdBlock detected
|
||||
# ???
|
||||
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;
|
||||
|
|
|
@ -5,7 +5,8 @@ from typing import Optional, Union, List
|
|||
from . import atserver
|
||||
from . import atconnect
|
||||
from . import aterrors
|
||||
from . import client_secrets
|
||||
|
||||
from .aterrors import AternosCredentialsError
|
||||
|
||||
class Client:
|
||||
|
||||
|
@ -13,48 +14,58 @@ class Client:
|
|||
|
||||
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
|
||||
def from_hashed(cls, username:str, md5:str):
|
||||
|
||||
atconn = atconnect.AternosConnect()
|
||||
token = atconn.parse_token()
|
||||
sec = atconn.generate_sec()
|
||||
atconn.parse_token()
|
||||
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',
|
||||
atconnect.REQPOST, data=self.credentials,
|
||||
atconnect.REQPOST, data=credentials,
|
||||
sendtoken=True
|
||||
)
|
||||
|
||||
if loginreq.cookies.get('ATERNOS_SESSION', None) == None:
|
||||
raise aterrors.AternosCredentialsError(
|
||||
raise AternosCredentialsError(
|
||||
'Check your username and password'
|
||||
)
|
||||
|
||||
cls(atconn)
|
||||
return cls(atconn)
|
||||
|
||||
@classmethod
|
||||
def from_credentials(cls, username:str, password:str):
|
||||
cls.from_hashed(
|
||||
username,
|
||||
hashlib.md5(password.encode('utf-8'))\
|
||||
.hexdigest().lower()
|
||||
)
|
||||
|
||||
pswd_bytes = password.encode('utf-8')
|
||||
md5 = hashlib.md5(pswd_bytes).hexdigest().lower()
|
||||
|
||||
return cls.from_hashed(username, md5)
|
||||
|
||||
@classmethod
|
||||
def with_google(cls):
|
||||
pass
|
||||
def from_session(cls, session:str):
|
||||
|
||||
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
|
||||
def servers(self) -> List[atserver.AternosServer]:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import enum
|
||||
import re
|
||||
import lxml.html
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
@ -8,68 +9,75 @@ from . import atconnect
|
|||
if TYPE_CHECKING:
|
||||
from atserver import AternosServer
|
||||
|
||||
OPT_PLAYERS = 'max-players'
|
||||
OPT_GAMEMODE = 'gamemode'
|
||||
OPT_DIFFICULTY = 'difficulty'
|
||||
OPT_WHITELIST = 'white-list'
|
||||
OPT_ONLINE = 'online-mode'
|
||||
OPT_PVP = 'pvp'
|
||||
OPT_CMDBLOCK = 'enable-command-block'
|
||||
OPT_FLIGHT = 'allow-flight'
|
||||
OPT_ANIMALS = 'spawn-animals'
|
||||
OPT_MONSTERS = 'spawn-monsters'
|
||||
OPT_VILLAGERS = 'spawn-npcs'
|
||||
OPT_NETHER = 'allow-nether'
|
||||
OPT_FORCEGM = 'force-gamemode'
|
||||
OPT_SPAWNLOCK = 'spawn-protection'
|
||||
OPT_CHEATS = 'allow-cheats'
|
||||
OPT_RESOURCEPACK = 'resource-pack'
|
||||
class ServerOpts(enum.Enum):
|
||||
players = 'max-players'
|
||||
gm = 'gamemode'
|
||||
difficulty = 'difficulty'
|
||||
whl = 'white-list'
|
||||
online = 'online-mode'
|
||||
pvp = 'pvp'
|
||||
cmdblock = 'enable-command-block'
|
||||
flight = 'allow-flight'
|
||||
animals = 'spawn-animals'
|
||||
monsters = 'spawn-monsters'
|
||||
villagers = 'spawn-npcs'
|
||||
nether = 'allow-nether'
|
||||
forcegm = 'force-gamemode'
|
||||
spawnlock = 'spawn-protection'
|
||||
cmds = 'allow-cheats'
|
||||
pack = 'resource-pack'
|
||||
|
||||
DAT_PREFIX = 'Data:'
|
||||
DAT_SEED = 'RandomSeed'
|
||||
DAT_HARDCORE = 'hardcore'
|
||||
DAT_DIFFICULTY = 'Difficulty'
|
||||
|
||||
class WorldOpts(enum.Enum):
|
||||
seed = 'randomseed'
|
||||
hardcore = 'hardcore'
|
||||
difficulty = 'difficulty'
|
||||
|
||||
DAT_GR_PREFIX = 'Data:GameRules:'
|
||||
DAT_GR_ADVS = 'announceAdvancements'
|
||||
DAT_GR_CMDOUT = 'commandBlockOutput'
|
||||
DAT_GR_ELYTRA = 'disableElytraMovementCheck'
|
||||
DAT_GR_DAYLIGHT = 'doDaylightCycle'
|
||||
DAT_GR_ENTDROPS = 'doEntityDrops'
|
||||
DAT_GR_FIRETICK = 'doFireTick'
|
||||
DAT_GR_LIMITCRAFT = 'doLimitedCrafting'
|
||||
DAT_GR_MOBLOOT = 'doMobLoot'
|
||||
DAT_GR_MOBS = 'doMobSpawning'
|
||||
DAT_GR_TILEDROPS = 'doTileDrops'
|
||||
DAT_GR_WEATHER = 'doWeatherCycle'
|
||||
DAT_GR_KEEPINV = 'keepInventory'
|
||||
DAT_GR_DEATHMSG = 'showDeathMessages'
|
||||
DAT_GR_ADMINCMDLOG = 'logAdminCommands'
|
||||
DAT_GR_CMDLEN = 'maxCommandChainLength'
|
||||
DAT_GR_ENTCRAM = 'maxEntityCramming'
|
||||
DAT_GR_MOBGRIEF = 'mobGriefing'
|
||||
DAT_GR_REGEN = 'naturalRegeneration'
|
||||
DAT_GR_RNDTICK = 'randomTickSpeed'
|
||||
DAT_GR_SPAWNRADIUS = 'spawnRadius'
|
||||
DAT_GR_REDUCEDF3 = 'reducedDebugInfo'
|
||||
DAT_GR_SPECTCHUNK = 'spectatorsGenerateChunks'
|
||||
DAT_GR_CMDFB = 'sendCommandFeedback'
|
||||
|
||||
class WorldRules(enum.Enum):
|
||||
advs = 'announceadvancements'
|
||||
cmdout = 'commandblockoutput'
|
||||
elytra = 'disableelytramovementcheck'
|
||||
daynight = 'dodaylightcycle'
|
||||
entdrop = 'doentitydrops'
|
||||
fire = 'dofiretick'
|
||||
limitcraft = 'dolimitedcrafting'
|
||||
mobloot = 'domobloot'
|
||||
mobs = 'domobspawning'
|
||||
blockdrop = 'dotiledrops'
|
||||
weather = 'doweathercycle'
|
||||
keepinv = 'keepinventory'
|
||||
deathmsg = 'showdeathmessages'
|
||||
admincmdlog = 'logadmincommands'
|
||||
cmdlen = 'maxcommandchainlength'
|
||||
entcram = 'maxentitycramming'
|
||||
mobgrief = 'mobgriefing'
|
||||
regen = 'naturalregeneration'
|
||||
rndtick = 'randomtickspeed'
|
||||
spawnradius = 'spawnradius'
|
||||
reducedf3 = 'reduceddebuginfo'
|
||||
spectchunkgen = 'spectatorsgeneratechunks'
|
||||
cmdfb = 'sendcommandfeedback'
|
||||
|
||||
DAT_TYPE_WORLD = 0
|
||||
DAT_TYPE_GR = 1
|
||||
|
||||
GM_SURVIVAL = 0
|
||||
GM_CREATIVE = 1
|
||||
GM_ADVENTURE = 2
|
||||
GM_SPECTATOR = 3
|
||||
class Gamemode(enum.IntEnum):
|
||||
survival = 0
|
||||
creative = 1
|
||||
adventure = 2
|
||||
spectator = 3
|
||||
|
||||
DF_PEACEFUL = 0
|
||||
DF_EASY = 1
|
||||
DF_NORMAL = 2
|
||||
DF_HARD = 3
|
||||
class Difficulty(enum.IntEnum):
|
||||
peaceful = 0
|
||||
easy = 1
|
||||
normal = 2
|
||||
hard = 3
|
||||
|
||||
JAVA_JDK = 'openjdk:{}'
|
||||
JAVA_OPENJ9 = 'adoptopenjdk:{}-jre-openj9-bionic'
|
||||
JDK = 'openjdk:{}'
|
||||
OJ9 = 'adoptopenjdk:{}-jre-openj9-bionic'
|
||||
|
||||
FLAG_PROP_TYPE = 1
|
||||
|
||||
|
@ -81,6 +89,7 @@ class AternosConfig:
|
|||
|
||||
@property
|
||||
def timezone(self) -> str:
|
||||
|
||||
optreq = self.atserv.atserver_request(
|
||||
'https://aternos.org/options',
|
||||
atconnect.REQGET
|
||||
|
@ -93,6 +102,7 @@ class AternosConfig:
|
|||
|
||||
@timezone.setter
|
||||
def timezone(self, value:str) -> None:
|
||||
|
||||
matches_tz = re.search(r'(?:^[A-Z]\w+\/[A-Z]\w+$)|^UTC$', value)
|
||||
if matches_tz == None:
|
||||
raise AttributeError('Timezone must match zoneinfo format: Area/Location')
|
||||
|
@ -105,6 +115,7 @@ class AternosConfig:
|
|||
|
||||
@property
|
||||
def java_version(self) -> str:
|
||||
|
||||
optreq = self.atserv.atserver_request(
|
||||
'https://aternos.org/options',
|
||||
atconnect.REQGET
|
||||
|
@ -117,9 +128,9 @@ class AternosConfig:
|
|||
|
||||
@java_version.setter
|
||||
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:
|
||||
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(
|
||||
'https://aternos.org/panel/ajax/image.php',
|
||||
|
@ -149,6 +160,7 @@ class AternosConfig:
|
|||
def set_world_prop(
|
||||
self, option:str, value:Any,
|
||||
proptype:int, world:str='world') -> None:
|
||||
|
||||
prefix = DAT_PREFIX
|
||||
if proptype == DAT_TYPE_GR:
|
||||
prefix = DAT_GR_PREFIX
|
||||
|
@ -162,6 +174,7 @@ class AternosConfig:
|
|||
def get_world_props(
|
||||
self, world:str='world',
|
||||
flags:int=FLAG_PROP_TYPE) -> Dict[str,Any]:
|
||||
|
||||
self.__get_all_props(
|
||||
f'https://aternos.org/files/{world}/level.dat',
|
||||
flags, [DAT_PREFIX, DAT_GR_PREFIX]
|
||||
|
|
|
@ -36,6 +36,8 @@ class AternosConnect:
|
|||
js_code = re.findall(r'\(\(\)(.*?)\)\(\);', text)
|
||||
token_func = js_code[1] if len(js_code) > 1 else js_code[0]
|
||||
|
||||
print('*** Function:', token_func)
|
||||
|
||||
ctx = atjsparse.exec(token_func)
|
||||
self.token = ctx.window['AJAX_TOKEN']
|
||||
|
||||
|
@ -64,95 +66,86 @@ class AternosConnect:
|
|||
for i in range(randlen+1):
|
||||
rand_arr.append('')
|
||||
|
||||
rand_alphanum = \
|
||||
self.convert_num(random.random(),36) + \
|
||||
'00000000000000000'
|
||||
return (rand_alphanum[2:18].join(rand_arr)[:randlen])
|
||||
rand = random.random()
|
||||
rand_alphanum = self.convert_num(rand, 36) + ('0' * 17)
|
||||
|
||||
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 = ''
|
||||
while num > 0:
|
||||
result = str(num % base) + result
|
||||
rem = num % base
|
||||
result = str(basesym[rem]) + result
|
||||
num //= base
|
||||
return result
|
||||
|
||||
def request_cloudflare(
|
||||
self, url:str, method:int,
|
||||
retries:int=10,
|
||||
params:Optional[dict]=None,
|
||||
data:Optional[dict]=None,
|
||||
headers:Optional[dict]=None,
|
||||
reqcookies:Optional[dict]=None,
|
||||
sendtoken:bool=False) -> Response:
|
||||
self, url:str, method:int, retries:int=10,
|
||||
params:Optional[dict]=None, data:Optional[dict]=None,
|
||||
headers:Optional[dict]=None, reqcookies:Optional[dict]=None,
|
||||
sendtoken:bool=False, redirect:bool=True) -> Response:
|
||||
|
||||
cftitle = '<title>Please Wait... | Cloudflare</title>'
|
||||
|
||||
if sendtoken:
|
||||
url += f'?TOKEN={self.token}&SEC={self.sec}'
|
||||
if params == None:
|
||||
params = {}
|
||||
|
||||
if headers == None:
|
||||
headers = {}
|
||||
headers['User-Agent'] = REQUA
|
||||
|
||||
if sendtoken:
|
||||
url += f'?TOKEN={self.token}&SEC={self.sec}'
|
||||
|
||||
try:
|
||||
cookies = self.session.cookies
|
||||
except AttributeError:
|
||||
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
|
||||
while cftitle in req.text \
|
||||
and (countdown > 0):
|
||||
while True:
|
||||
|
||||
self.session = CloudScraper()
|
||||
if cookies != None:
|
||||
self.session.cookies = cookies
|
||||
|
||||
if reqcookies != None:
|
||||
for cookiekey in reqcookies:
|
||||
self.session.cookies.set(cookiekey, reqcookies[cookiekey])
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
if method == REQPOST:
|
||||
req = self.session.post(
|
||||
url,
|
||||
data=data,
|
||||
headers=headers,
|
||||
cookies=reqcookies
|
||||
url, data=data, params=params,
|
||||
headers=headers, cookies=reqcookies,
|
||||
allow_redirects=redirect
|
||||
)
|
||||
else:
|
||||
req = self.session.get(
|
||||
url,
|
||||
params=params,
|
||||
headers=headers,
|
||||
cookies=reqcookies
|
||||
url, params=params,
|
||||
headers=headers, cookies=reqcookies,
|
||||
allow_redirects=redirect
|
||||
)
|
||||
|
||||
if not cftitle in req.text:
|
||||
break
|
||||
if not countdown > 0:
|
||||
raise aterrors.CloudflareError(
|
||||
'The retries limit has been reached'
|
||||
)
|
||||
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
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
class AternosError(Exception):
|
||||
|
||||
pass
|
||||
|
||||
class AternosCredentialsError(AternosError):
|
||||
|
||||
pass
|
||||
|
||||
class AternosServerStartError(AternosError):
|
||||
|
||||
pass
|
||||
|
||||
class AternosIOError(AternosError):
|
||||
|
||||
pass
|
||||
|
||||
class CloudflareError(AternosError):
|
||||
pass
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import enum
|
||||
import re
|
||||
import json
|
||||
import lxml.html
|
||||
import websockets
|
||||
from requests import Response
|
||||
from typing import Optional, Dict
|
||||
|
||||
|
@ -10,26 +12,33 @@ from . import atfm
|
|||
from . import atconf
|
||||
from . import atplayers
|
||||
|
||||
SOFTWARE_JAVA = 0
|
||||
SOFTWARE_BEDROCK = 1
|
||||
JAVA = 0
|
||||
BEDROCK = 1
|
||||
|
||||
PLAYERS_ALLOWED = 'whitelist'
|
||||
PLAYERS_OPS = 'ops'
|
||||
PLAYERS_BANNED = 'banned-players'
|
||||
PLAYERS_IPS = 'banned-ips'
|
||||
class Lists(enum.Enum):
|
||||
whl = 'whitelist'
|
||||
ops = 'ops'
|
||||
ban = 'banned-players'
|
||||
ips = 'banned-ips'
|
||||
|
||||
STATUS_OFFLINE = 0
|
||||
STATUS_ONLINE = 1
|
||||
STATUS_LOADING = 2
|
||||
STATUS_SHUTDOWN = 3
|
||||
STATUS_ERROR = 7
|
||||
class Status(enum.IntEnum):
|
||||
off = 0
|
||||
on = 1
|
||||
loading = 2
|
||||
shutdown = 3
|
||||
error = 7
|
||||
|
||||
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.atconn = atconn
|
||||
self.savelog = savelog
|
||||
self.log = []
|
||||
|
||||
servreq = self.atserver_request(
|
||||
'https://aternos.org/server',
|
||||
|
@ -43,36 +52,91 @@ class AternosServer:
|
|||
servtree.head.text_content()
|
||||
)[1]
|
||||
)
|
||||
self._ram = 0
|
||||
self._tps = 0
|
||||
|
||||
self.atconn.parse_token(servreq.content)
|
||||
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(
|
||||
'https://aternos.org/panel/ajax/start.php',
|
||||
atconnect.REQGET, sendtoken=True
|
||||
atconnect.REQGET, params={'headstart': int(headstart)},
|
||||
sendtoken=True
|
||||
)
|
||||
startresult = startreq.json()
|
||||
|
||||
if startresult['success']:
|
||||
return
|
||||
|
||||
error = startresult['error']
|
||||
|
||||
if error == 'eula' and accepteula:
|
||||
self.eula()
|
||||
self.start(accepteula=False)
|
||||
|
||||
elif error == 'eula':
|
||||
raise aterrors.AternosServerStartError(
|
||||
'EULA was not accepted. Use start(accepteula=True)'
|
||||
)
|
||||
|
||||
elif error == 'already':
|
||||
raise aterrors.AternosServerStartError(
|
||||
'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:
|
||||
raise aterrors.AternosServerStartError(
|
||||
f'Unable to start server. Code: {error}'
|
||||
f'Unable to start server, code: {error}'
|
||||
)
|
||||
|
||||
def confirm(self) -> None:
|
||||
|
@ -120,6 +184,14 @@ class AternosServer:
|
|||
|
||||
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)
|
||||
|
||||
def atserver_request(
|
||||
|
@ -129,7 +201,6 @@ class AternosServer:
|
|||
headers:Optional[dict]=None,
|
||||
sendtoken:bool=False) -> Response:
|
||||
|
||||
print(sendtoken)
|
||||
return self.atconn.request_cloudflare(
|
||||
url=url, method=method,
|
||||
params=params, data=data,
|
||||
|
@ -149,7 +220,8 @@ class AternosServer:
|
|||
def subdomain(self, value:str) -> None:
|
||||
self.atserver_request(
|
||||
'https://aternos.org/panel/ajax/options/subdomain.php',
|
||||
atconnect.REQGET, params={'subdomain': value}
|
||||
atconnect.REQGET, params={'subdomain': value},
|
||||
sendtoken=True
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -179,10 +251,7 @@ class AternosServer:
|
|||
@property
|
||||
def edition(self) -> int:
|
||||
soft_type = self._info['bedrock']
|
||||
if soft_type == True:
|
||||
return SOFTWARE_BEDROCK
|
||||
else:
|
||||
return SOFTWARE_JAVA
|
||||
return int(soft_type)
|
||||
|
||||
@property
|
||||
def software(self) -> str:
|
||||
|
@ -198,4 +267,4 @@ class AternosServer:
|
|||
|
||||
@property
|
||||
def ram(self) -> int:
|
||||
return int(self._info['ram'])
|
||||
return self._ram
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
CSJSON = 'eyJpbnN0YWxsZWQiOnsiY2xpZW50X2lkIjoiNjU4MTQyNjkxNjQxLXFnZ21sdGNmdXY0a2I1a2NwczdoZjBiaGlvN2Q0dnUzLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwicHJvamVjdF9pZCI6InB5dGhvbi1hdGVybm9zIiwiYXV0aF91cmkiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvYXV0aCIsInRva2VuX3VyaSI6Imh0dHBzOi8vb2F1dGgyLmdvb2dsZWFwaXMuY29tL3Rva2VuIiwiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwiY2xpZW50X3NlY3JldCI6IkdPQ1NQWC1XUUJsMjIzOTZxcHVLMDJIVXVpWUhhUXNmbC03IiwicmVkaXJlY3RfdXJpcyI6WyJ1cm46aWV0Zjp3ZzpvYXV0aDoyLjA6b29iIiwiaHR0cDovL2xvY2FsaG9zdCJdfX0='
|
|
@ -1,4 +1,5 @@
|
|||
lxml==4.6.2
|
||||
requests==2.25.1
|
||||
cloudscraper==1.2.58
|
||||
Js2Py==0.71
|
||||
js2py==0.71
|
||||
websockets==10.1
|
||||
|
|
13
setup.py
13
setup.py
|
@ -3,9 +3,14 @@ import setuptools
|
|||
with open('README.md', 'rt') as readme:
|
||||
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(
|
||||
name='python-aternos',
|
||||
version='0.5',
|
||||
version='0.6',
|
||||
author='Chechkenev Andrey (@DarkCat09)',
|
||||
author_email='aacd0709@mail.ru',
|
||||
description='An unofficial Aternos API',
|
||||
|
@ -21,11 +26,7 @@ setuptools.setup(
|
|||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent'
|
||||
],
|
||||
install_requires=[
|
||||
'lxml==4.6.2',
|
||||
'requests==2.25.1',
|
||||
'cloudscraper==1.2.58'
|
||||
],
|
||||
install_requires=requires,
|
||||
packages=['python_aternos'],
|
||||
python_requires=">=3.6",
|
||||
)
|
||||
|
|
Reference in a new issue