reconnect logic, action queue + reactionary actions

This commit is contained in:
Ra 2022-03-10 23:37:56 -07:00
parent 253a8ad708
commit d7dfd654ef
3 changed files with 92 additions and 47 deletions

@ -1,16 +1,32 @@
from asyncio import sleep
from .client_base import ClientBase
from .packet import packet_handler, oPacket
from .opcodes import RecvOps, SendOps
class Client(ClientBase):
def __init__(self, loop=None, username=None, password=None):
super().__init__(loop)
self._username = username
self._password = password
async def begin(self):
# opkt = oPacket(SendOps.LOGIN_PASSWORD)
...
while self._loop.is_running() and self._sock.fileno():
action = await self._action_queue.get()
match action:
case SendOps.LOGIN_PASSWORD:
self._loop.create_task(self.do_login())
@packet_handler(RecvOps.PING)
async def pong(self, ipkt):
print("Sending PONG packet")
await sleep(1)
opkt = oPacket(SendOps.PONG)
await self.send_packet(opkt)
async def do_login(self):
opkt = oPacket(SendOps.LOGIN_PASSWORD)
opkt.encode_string(self._username)
opkt.encode_string(self._password)
await self.send_packet(opkt)

@ -1,11 +1,9 @@
from asyncio import Event, get_event_loop, get_running_loop, run_coroutine_threadsafe, sleep, Lock
from asyncio import Event, get_event_loop, get_running_loop, run_coroutine_threadsafe, sleep, Lock, Queue, Task
from socket import AF_INET, IPPROTO_TCP, SOCK_STREAM, TCP_NODELAY, socket
from .packet import PacketHandler, Packet, iPacket, oPacket
from .crypto import MapleAes, decrypt_transform, encrypt_transform, MapleIV
from rich import print
VERSION = 111
class ClientBase:
@ -14,20 +12,26 @@ class ClientBase:
self._packet_handlers = []
self._ready = Event()
self._lock = Lock()
self._action_queue = Queue()
self._action_task: Task | None = None
self._sock = socket(AF_INET, SOCK_STREAM)
self._sock.setblocking(False)
self._sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
self._sock: socket
self._version = None
self._sub_version = None
self._locale = None
self._recv_iv = None
self._send_iv = None
self._recv_iv: MapleIV | None = None
self._send_iv: MapleIV | None = None
self._buff = bytearray()
self._recv_task = None
self.add_packet_handlers()
def _create_sock(self):
self._sock = socket(AF_INET, SOCK_STREAM)
self._sock.setblocking(False)
self._sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
async def start(self):
self._create_sock()
self._recv_task = self._loop.create_task(self._sock_recv())
self._ready.set()
@ -43,45 +47,70 @@ class ClientBase:
await self._loop.sock_sendall(self._sock, header + opkt)
async def _sock_recv(self):
await self._loop.sock_connect(self._sock, ("51.222.56.169", 8485))
# 51.222.56.169
await self._ready.wait()
nbytes = -1
while self._loop.is_running():
while self._loop.is_running() and self._sock.fileno():
self._buff.extend((await self._loop.sock_recv(self._sock, nbytes)))
await self._loop.sock_connect(self._sock, ("51.222.56.169", 8485))
nbytes = -1
if not self._send_iv and self._buff:
begin_packet = iPacket(self._buff)
self._version = begin_packet.decode_short()
self._sub_version = begin_packet.decode_string()
self._send_iv = MapleIV(begin_packet.decode_int())
self._recv_iv = MapleIV(begin_packet.decode_int())
self._locale = begin_packet.decode_byte()
await getattr(self, "begin")()
print(
f"Version: {self._version} | Sub Version: {self._sub_version} | Locale: {self._locale} | Send IV: {self._send_iv} | Recv IV: {self._recv_iv}"
)
self._buff = bytearray()
continue
while self._sock.fileno():
try:
self._buff.extend(
(await self._loop.sock_recv(self._sock, nbytes)))
except ConnectionResetError:
print("Connection reset, attempting to reconnect..")
self._create_sock()
self._send_iv = None
self._recv_iv = None
if self._action_task:
self._action_task.cancel()
self._action_queue = Queue()
break
if self._buff:
length = MapleAes.get_length(self._buff[0:4])
if length != len(self._buff[4:]):
nbytes = length - len(self._buff[4:])
else:
nbytes = -1
buf = bytearray(self._buff)[4:]
if length == len(buf):
buf = MapleAes.transform(buf, self._recv_iv)
buf = decrypt_transform(buf)
packet = iPacket(buf)
if not self._send_iv and self._buff:
begin_packet = iPacket(self._buff)
op_code = 0x0E
self._version = begin_packet.decode_short()
self._sub_version = begin_packet.decode_string()
self._send_iv = MapleIV(begin_packet.decode_int())
self._recv_iv = MapleIV(begin_packet.decode_int())
self._locale = begin_packet.decode_byte()
# print(begin_packet)
self._action_task = self._loop.create_task(
getattr(self, "begin")())
print(
f"Op Code: {op_code} [Client Hello] | Version: {self._version} | Sub Version: {self._sub_version} | Locale: {self._locale} | Send IV: {self._send_iv} | Recv IV: {self._recv_iv}"
)
self._buff = bytearray()
continue
self.handle_packet(packet)
if self._buff and len(self._buff) > 4:
length = MapleAes.get_length(self._buff[0:4])
if length != len(self._buff[4:length + 4]):
print(
f"expected length: {length} | actual length: {len(self._buff[4:length+4])}"
)
nbytes = length - len(self._buff[4:length + 4])
else:
nbytes = -1
await sleep(0.5)
buf = bytearray(self._buff)[4:length + 4]
print(
f"buffer size: {length} | raw buffer: {self._buff} | data buffer: {buf}"
)
if length == len(buf):
buf = MapleAes.transform(buf, self._recv_iv)
buf = decrypt_transform(buf)
packet = iPacket(buf)
self._buff = bytearray()
self.handle_packet(packet)
def handle_packet(self, packet):
coro = None

@ -19,10 +19,10 @@ class MapleAes:
real_iv = bytearray(16)
iv_bytes = [
iv.value & 255,
iv.value >> 8 & 255,
iv.value >> 16 & 255,
iv.value >> 24 & 255,
iv.value & 0xFF,
iv.value >> 8 & 0xFF,
iv.value >> 16 & 0xFF,
iv.value >> 24 & 0xFF,
]
while remaining > 0:
@ -98,7 +98,7 @@ class MapleIV:
return self.value
def __str__(self):
return self.value
return str(self.value)
@property
def hiword(self):