async def recv_data(self): data_len = 0 buff = tmp_file() try: with buff.open('wb') as fh: while chunk_size := as_uint(await self.conn.read(4)): if chunk_size > MAX_IN_MEMORY: data_len += await self._recv_large_chunk( fh, chunk_size) else: data_len += await self._recv_small_chunk( fh, chunk_size) if data_len > self.conn.conf.max_plain_payload: if self.data_type != T_FILE: raise ProtocolError( f'Attempted to send message larger than ' f'{format_amount(self.conn.conf.max_plain_payload)}', conn=self.conn) decode = buff elif self.data_type != T_FILE: with buff.open('rb') as _fh: decode = _fh.read() self.data = await Codec.decode(decode, self.data_type, self.headers) self.data_len = data_len
async def init(self): await self.write(to_uint(self.PROTOCOL_VERSION, 4)) result = await self.read(4) if result != bytes(4): raise ProtocolError( f'Unsupported protocol version. ' f'Please upgrade your client to: {as_uint(result)}', conn=self ) client_stmt = ClientStatement( api=self.api_version, client_time=time_ns() // 1000_000, scheme_format='JSON', compressors=['gzip', 'zlib'], default_compression='zlib', ) self.set_compressors(['gzip', 'zlib'], 'zlib') await self.write(client_stmt.pack()) stmt: ServerStatement = ServerStatement.unpack( await self.read(as_uint(await self.read(4))) ) self.time_delta = (stmt.server_time / 1000) - time() if self.conf.handshake is not None: await self.conf.handshake.send(self) self.debug(f'{self} initialized')
async def decompress_file(cls, src: Path, dst: Path, headers: T_Headers) -> None: compressor = zlib.decompressobj() value = 1 with src.open('rb') as rc: with dst.open('wb') as wc: ln = as_uint(rc.read(4)) while line := rc.read(1 << 24): wc.write(buff := compressor.decompress(line)) value = zlib.adler32(buff, value) wc.write(compressor.flush())
async def init(cls, conn): head = await cls._recv_head(conn) headers_size = as_uint(await conn.read(4)) headers = Headers.decode(await conn.read(headers_size)) conn.debug( f'[RECV {conn.address}] [{int2hex(head.message_id):<4}] <- HEADERS {headers}' ) action = cls(**vars(head), headers=headers) action.conn = conn return action
async def decompress(cls, data: bytes, headers: T_Headers) -> bytes: ln, data = as_uint(data[:4]), data[4:] buff = zlib.decompress(data) checksum = headers.get('Adler32', None) if ln != len(buff): raise CompressorError('Broken data received: Length mismatch', data=data, headers=headers) if checksum is not None and zlib.adler32(buff) != checksum: raise CompressorError('Broken data received: Checksum mismatch', data=data, headers=headers) return buff
async def handle_stream(self, stream: IOStream, address: tuple[str, int]) -> None: try: protocol_version = as_uint(await stream.read_bytes(4)) if not self.protocols[0] <= protocol_version <= self.protocols[1]: await stream.write(to_uint(self.protocols[1], 4)) stream.close(CatsError('Unsupported protocol version')) return await stream.write(bytes(4)) async with self.create_connection(stream, address, protocol_version) as conn: conn: ServerConnection conn.debug(f'[INIT {address}]') await conn.init() await conn.start() conn.debug(f'[STOP {address}]') except self.app.config.stream_errors: pass
async def init(self): self.client: ClientStatement = ClientStatement.unpack( await self.read(as_uint(await self.read(4))) ) self.api_version = self.client.api self.set_compressors(self.client.compressors, self.client.default_compression) self.debug(f'[RECV {self.address}] {self.client}') server_stmt = ServerStatement( server_time=time_ns() // 1000_000, ) await self.write(server_stmt.pack()) self.debug(f'[SEND {self.address}] {server_stmt}') if self.conf.handshake is not None: await self.conf.handshake.validate(self) self.debug(f'{self} initialized')