Completely overhaul connections and transports

Reduce abstraction leaks. Now the transport can hold any state,
rather than just the tag. It's also responsible to initialize on
the first connection, and they can be cleanly reset.

asyncio connections are no longer used, in favour of raw sockets,
which should avoid some annoyances.

For the time being, more obscure transport modes have been removed,
as well as proxy support, until further cleaning is done.
This commit is contained in:
Lonami Exo
2022-01-15 13:33:50 +01:00
parent 02703e3753
commit f5f0c84553
18 changed files with 221 additions and 853 deletions

View File

@@ -0,0 +1,61 @@
import asyncio
import socket
from .transports.transport import Transport
CHUNK_SIZE = 32 * 1024
# TODO ideally the mtproto impl would also be sans-io, but that's less pressing
class Connection:
def __init__(self, ip, port, *, transport: Transport, loggers, local_addr=None):
self._ip = ip
self._port = port
self._log = loggers[__name__]
self._local_addr = local_addr
self._sock = None
self._in_buffer = bytearray()
self._transport = transport
async def connect(self, timeout=None, ssl=None):
"""
Establishes a connection with the server.
"""
loop = asyncio.get_event_loop()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(False)
if self._local_addr:
sock.bind(self._local_addr)
await asyncio.wait_for(loop.sock_connect(sock, (self._ip, self._port)), timeout)
self._sock = sock
async def disconnect(self):
self._sock.close()
self._sock = None
async def send(self, data):
if not self._sock:
raise ConnectionError('not connected')
loop = asyncio.get_event_loop()
await loop.sock_sendall(self._sock, self._transport.pack(data))
async def recv(self):
if not self._sock:
raise ConnectionError('not connected')
loop = asyncio.get_event_loop()
while True:
try:
length, body = self._transport.unpack(self._in_buffer)
del self._in_buffer[:length]
return body
except EOFError:
self._in_buffer += await loop.sock_recv(self._sock, CHUNK_SIZE)
def __str__(self):
return f'{self._ip}:{self._port}/{self._transport.__class__.__name__}'