2022-01-22 15:10:30 +04:00
|
|
|
import enum
|
|
|
|
import json
|
|
|
|
import asyncio
|
2022-04-06 11:44:14 +04:00
|
|
|
import logging
|
2022-01-22 15:10:30 +04:00
|
|
|
import websockets
|
|
|
|
from typing import Union, Any, Dict, Callable, Coroutine
|
2022-03-25 16:45:38 +04:00
|
|
|
from typing import TYPE_CHECKING
|
2022-01-22 15:10:30 +04:00
|
|
|
|
|
|
|
from .atconnect import REQUA
|
2022-03-25 16:45:38 +04:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from .atserver import AternosServer
|
2022-01-22 15:10:30 +04:00
|
|
|
|
2022-04-06 11:44:14 +04:00
|
|
|
class Streams(enum.Enum):
|
|
|
|
|
|
|
|
status = (0,None)
|
|
|
|
queue = (1,None)
|
|
|
|
console = (2,'console')
|
|
|
|
ram = (3,'heap')
|
|
|
|
tps = (4,'tick')
|
|
|
|
|
|
|
|
def __init__(self, num:int, stream:str):
|
|
|
|
self.num = num
|
|
|
|
self.stream = stream
|
2022-01-22 15:10:30 +04:00
|
|
|
|
|
|
|
class AternosWss:
|
|
|
|
|
2022-03-25 16:45:38 +04:00
|
|
|
def __init__(self, atserv:'AternosServer', autoconfirm:bool=False) -> None:
|
2022-01-22 15:10:30 +04:00
|
|
|
|
2022-03-25 16:45:38 +04:00
|
|
|
self.atserv = atserv
|
|
|
|
self.cookies = atserv.atconn.session.cookies
|
|
|
|
self.session = self.cookies['ATERNOS_SESSION']
|
2022-04-06 11:44:14 +04:00
|
|
|
self.servid = atserv.servid
|
2022-01-22 15:10:30 +04:00
|
|
|
self.recv = {}
|
2022-03-25 16:45:38 +04:00
|
|
|
self.autoconfirm = autoconfirm
|
|
|
|
self.confirmed = False
|
|
|
|
|
|
|
|
async def confirm(self) -> None:
|
|
|
|
|
|
|
|
self.atserv.confirm()
|
2022-01-22 15:10:30 +04:00
|
|
|
|
2022-04-06 11:44:14 +04:00
|
|
|
def wssreceiver(self, stream:Streams) -> Callable[[Callable[[Any],Coroutine[Any,Any,None]]],Any]:
|
2022-01-22 15:10:30 +04:00
|
|
|
def decorator(func:Callable[[Any],Coroutine[Any,Any,None]]) -> None:
|
|
|
|
self.recv[stream] = func
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
async def connect(self) -> None:
|
|
|
|
|
|
|
|
headers = [
|
2022-03-25 16:45:38 +04:00
|
|
|
('Host', 'aternos.org'),
|
2022-01-22 15:10:30 +04:00
|
|
|
('User-Agent', REQUA),
|
|
|
|
(
|
|
|
|
'Cookie',
|
2022-03-25 16:45:38 +04:00
|
|
|
f'ATERNOS_SESSION={self.session}; ' + \
|
2022-01-22 15:10:30 +04:00
|
|
|
f'ATERNOS_SERVER={self.servid}'
|
|
|
|
)
|
|
|
|
]
|
|
|
|
self.socket = await websockets.connect(
|
2022-03-25 16:45:38 +04:00
|
|
|
'wss://aternos.org/hermes/',
|
|
|
|
origin='https://aternos.org',
|
2022-01-22 15:10:30 +04:00
|
|
|
extra_headers=headers
|
|
|
|
)
|
2022-04-06 11:44:14 +04:00
|
|
|
|
|
|
|
@self.wssreceiver(Streams.status)
|
|
|
|
async def confirmfunc(msg):
|
|
|
|
# Autoconfirm
|
|
|
|
if not self.autoconfirm:
|
|
|
|
return
|
|
|
|
if msg['class'] == 'queueing' \
|
|
|
|
and msg['queue']['pending'] == 'pending'\
|
|
|
|
and not self.confirmed:
|
|
|
|
self.confirm()
|
|
|
|
|
|
|
|
@self.wssreceiver(Streams.status)
|
|
|
|
async def streamsfunc(msg):
|
|
|
|
if msg['status'] == 2:
|
|
|
|
# Automatically start streams
|
|
|
|
for strm in self.recv:
|
|
|
|
if not isinstance(strm,Streams):
|
|
|
|
continue
|
|
|
|
if strm.stream:
|
|
|
|
logging.debug(f'Enabling {strm.stream} stream')
|
|
|
|
await self.send({
|
|
|
|
'stream': strm.stream,
|
|
|
|
'type': 'start'
|
|
|
|
})
|
2022-03-25 16:45:38 +04:00
|
|
|
|
|
|
|
await self.wssworker()
|
2022-01-22 15:10:30 +04:00
|
|
|
|
|
|
|
async def close(self) -> None:
|
|
|
|
|
|
|
|
await self.socket.close()
|
|
|
|
del self.socket
|
|
|
|
|
|
|
|
async def send(self, obj:Union[Dict[str, Any],str]) -> None:
|
|
|
|
|
|
|
|
if isinstance(obj, dict):
|
|
|
|
obj = json.dumps(obj)
|
|
|
|
|
2022-04-06 11:44:14 +04:00
|
|
|
await self.socket.send(obj)
|
2022-01-22 15:10:30 +04:00
|
|
|
|
|
|
|
async def wssworker(self) -> None:
|
|
|
|
|
2022-03-25 16:45:38 +04:00
|
|
|
keep = asyncio.create_task(self.keepalive())
|
|
|
|
msgs = asyncio.create_task(self.receiver())
|
2022-01-22 15:10:30 +04:00
|
|
|
await keep
|
|
|
|
await msgs
|
|
|
|
|
|
|
|
async def keepalive(self) -> None:
|
|
|
|
|
|
|
|
while True:
|
|
|
|
await asyncio.sleep(49)
|
|
|
|
await self.socket.send('{"type":"\u2764"}')
|
|
|
|
|
|
|
|
async def receiver(self) -> None:
|
|
|
|
|
|
|
|
while True:
|
|
|
|
data = await self.socket.recv()
|
|
|
|
obj = json.loads(data)
|
2022-04-06 11:44:14 +04:00
|
|
|
msgtype = -1
|
2022-01-22 15:10:30 +04:00
|
|
|
|
|
|
|
if obj['type'] == 'line':
|
|
|
|
msgtype = Streams.console
|
|
|
|
msg = obj['data'].strip('\r\n ')
|
|
|
|
|
|
|
|
elif obj['type'] == 'heap':
|
|
|
|
msgtype = Streams.ram
|
|
|
|
msg = int(obj['data']['usage'])
|
|
|
|
|
|
|
|
elif obj['type'] == 'tick':
|
|
|
|
msgtype = Streams.tps
|
|
|
|
ticks = 1000 / obj['data']['averageTickTime']
|
|
|
|
msg = 20 if ticks > 20 else ticks
|
|
|
|
|
|
|
|
elif obj['type'] == 'status':
|
|
|
|
msgtype = Streams.status
|
|
|
|
msg = json.loads(obj['message'])
|
|
|
|
|
|
|
|
if msgtype in self.recv:
|
|
|
|
t = asyncio.create_task(
|
|
|
|
self.recv[msgtype](msg)
|
|
|
|
)
|
|
|
|
await t
|