reconnect logic, action queue + reactionary actions
This commit is contained in:
parent
253a8ad708
commit
d7dfd654ef
20
client.py
20
client.py
@ -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)
|
109
client_base.py
109
client_base.py
@ -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
|
||||
|
10
crypto.py
10
crypto.py
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user