Module lib.server.stream
These classes are used to manage asynchronous stream.
Expand source code
# Distributed under Pycameresp License
# Copyright (c) 2023 Remi BERTHOLET
""" These classes are used to manage asynchronous stream. """
import io
import tools.filesystem
class Stream:
""" Class stream """
# trace = open("stream.txt","wb")
trace = None
def __init__(self, reader, writer):
self.reader = reader
self.writer = writer
self.buffer = b""
if tools.filesystem.ismicropython():
self.close = self.close_mcp
self.awrite = self.awrite_mcp
self.is_closing = self.is_closing_mcp
else:
self.close = self.close_pc
self.awrite = self.awrite_pc
self.is_closing = self.is_closing_pc
async def readline(self):
""" The firt time, this method completely reads the stream.
It then returns only the requested row. This significantly increases read performance. """
pos = self.buffer.find(b"\r\n")
if pos == -1:
self.buffer += await self.reader.read(1440)
pos = self.buffer.find(b"\r\n")
if pos == -1:
result = self.buffer
self.buffer = b""
else:
result = self.buffer[:pos+2]
self.buffer = self.buffer[pos+2:]
return result
async def read(self, length):
""" Read data from the stream """
if len(self.buffer) < length:
data = await self.reader.read(length - len(self.buffer))
self.buffer += data
data = self.buffer[:length]
self.buffer = self.buffer[length:]
if Stream.trace:
Stream.trace.write(b"\n# read\n")
Stream.trace.write(data)
Stream.trace.flush()
return data
async def write(self, data):
""" Write data in the stream """
result = await self.awrite(data)
if self.is_closing():
raise OSError(104,"Closed connection")
if Stream.trace:
Stream.trace.write(b"\n# write\n")
Stream.trace.write(data)
Stream.trace.flush()
if result is None:
result = len(data)
else:
result = -1
return result
async def awrite_mcp(self, data):
""" Awrite micropython """
return await self.writer.awrite(data)
async def awrite_pc(self, data):
""" Awrite micropython """
return self.writer.write(data)
async def close_mcp(self):
""" Close the stream """
await self.writer.aclose()
async def close_pc(self):
""" Close the stream """
self.writer.close()
def is_closing_pc(self):
""" Check if it closed """
return self.writer.is_closing()
def is_closing_mcp(self):
""" Check if it closed """
return False
class Socket:
""" Class stream which wrap socket """
def __init__(self, socket):
""" Constructor """
self.socket = socket
def read(self):
""" Read data from the stream """
data = self.socket.readlines()
return data
def write(self, data):
""" Write data in the stream """
length = self.socket.sendall(data)
if length is None:
length = len(data)
return length
def close(self):
""" Close the stream """
self.socket.close()
class Bytesio:
""" Class stream which wrap BytesIO """
def __init__(self):
""" Constructor """
self.streamio = io.BytesIO()
async def read(self):
""" Read data from the stream """
return self.streamio.read()
async def write(self, data):
""" Write data in the stream """
return self.streamio.write(data)
async def close(self):
""" Close the stream """
self.streamio.close()
class Bufferedio:
""" Bufferized bytes io stream """
memorysize = [None]
""" Class used to buffered stream write """
def __init__(self, streamio, part=1440*20):
""" Constructor """
self.buffered = io.BytesIO()
if Bufferedio.is_enough_memory():
self.part = part
else:
self.part = None
self.streamio = streamio
@staticmethod
def is_enough_memory():
""" Indicate if it has enough memory """
if Bufferedio.memorysize[0] is None:
import gc
try:
# pylint: disable=no-member
Bufferedio.memorysize[0] = gc.mem_free()
except:
Bufferedio.memorysize[0] = 256*1024
if Bufferedio.memorysize[0] < 200*1024:
return False
return True
async def read(self):
""" Read data from the stream """
return self.streamio.read()
async def write(self, data):
""" Write data in the stream """
if self.part is None:
result = len(data)
await self.streamio.write(data)
else:
result = self.buffered.write(data)
if self.buffered.tell() > self.part:
await self.streamio.write(self.buffered.getvalue())
self.buffered = io.BytesIO()
return result
async def close(self):
""" Close the stream """
try:
if self.buffered.tell() > 0:
await self.streamio.write(self.buffered.getvalue())
finally:
self.buffered.close()
Classes
class Bufferedio (streamio, part=28800)-
Bufferized bytes io stream
Constructor
Expand source code
class Bufferedio: """ Bufferized bytes io stream """ memorysize = [None] """ Class used to buffered stream write """ def __init__(self, streamio, part=1440*20): """ Constructor """ self.buffered = io.BytesIO() if Bufferedio.is_enough_memory(): self.part = part else: self.part = None self.streamio = streamio @staticmethod def is_enough_memory(): """ Indicate if it has enough memory """ if Bufferedio.memorysize[0] is None: import gc try: # pylint: disable=no-member Bufferedio.memorysize[0] = gc.mem_free() except: Bufferedio.memorysize[0] = 256*1024 if Bufferedio.memorysize[0] < 200*1024: return False return True async def read(self): """ Read data from the stream """ return self.streamio.read() async def write(self, data): """ Write data in the stream """ if self.part is None: result = len(data) await self.streamio.write(data) else: result = self.buffered.write(data) if self.buffered.tell() > self.part: await self.streamio.write(self.buffered.getvalue()) self.buffered = io.BytesIO() return result async def close(self): """ Close the stream """ try: if self.buffered.tell() > 0: await self.streamio.write(self.buffered.getvalue()) finally: self.buffered.close()Class variables
var memorysize-
Class used to buffered stream write
Static methods
def is_enough_memory()-
Indicate if it has enough memory
Expand source code
@staticmethod def is_enough_memory(): """ Indicate if it has enough memory """ if Bufferedio.memorysize[0] is None: import gc try: # pylint: disable=no-member Bufferedio.memorysize[0] = gc.mem_free() except: Bufferedio.memorysize[0] = 256*1024 if Bufferedio.memorysize[0] < 200*1024: return False return True
Methods
async def close(self)-
Close the stream
Expand source code
async def close(self): """ Close the stream """ try: if self.buffered.tell() > 0: await self.streamio.write(self.buffered.getvalue()) finally: self.buffered.close() async def read(self)-
Read data from the stream
Expand source code
async def read(self): """ Read data from the stream """ return self.streamio.read() async def write(self, data)-
Write data in the stream
Expand source code
async def write(self, data): """ Write data in the stream """ if self.part is None: result = len(data) await self.streamio.write(data) else: result = self.buffered.write(data) if self.buffered.tell() > self.part: await self.streamio.write(self.buffered.getvalue()) self.buffered = io.BytesIO() return result
class Bytesio-
Class stream which wrap BytesIO
Constructor
Expand source code
class Bytesio: """ Class stream which wrap BytesIO """ def __init__(self): """ Constructor """ self.streamio = io.BytesIO() async def read(self): """ Read data from the stream """ return self.streamio.read() async def write(self, data): """ Write data in the stream """ return self.streamio.write(data) async def close(self): """ Close the stream """ self.streamio.close()Methods
async def close(self)-
Close the stream
Expand source code
async def close(self): """ Close the stream """ self.streamio.close() async def read(self)-
Read data from the stream
Expand source code
async def read(self): """ Read data from the stream """ return self.streamio.read() async def write(self, data)-
Write data in the stream
Expand source code
async def write(self, data): """ Write data in the stream """ return self.streamio.write(data)
class Socket (socket)-
Class stream which wrap socket
Constructor
Expand source code
class Socket: """ Class stream which wrap socket """ def __init__(self, socket): """ Constructor """ self.socket = socket def read(self): """ Read data from the stream """ data = self.socket.readlines() return data def write(self, data): """ Write data in the stream """ length = self.socket.sendall(data) if length is None: length = len(data) return length def close(self): """ Close the stream """ self.socket.close()Methods
def close(self)-
Close the stream
Expand source code
def close(self): """ Close the stream """ self.socket.close() def read(self)-
Read data from the stream
Expand source code
def read(self): """ Read data from the stream """ data = self.socket.readlines() return data def write(self, data)-
Write data in the stream
Expand source code
def write(self, data): """ Write data in the stream """ length = self.socket.sendall(data) if length is None: length = len(data) return length
class Stream (reader, writer)-
Class stream
Expand source code
class Stream: """ Class stream """ # trace = open("stream.txt","wb") trace = None def __init__(self, reader, writer): self.reader = reader self.writer = writer self.buffer = b"" if tools.filesystem.ismicropython(): self.close = self.close_mcp self.awrite = self.awrite_mcp self.is_closing = self.is_closing_mcp else: self.close = self.close_pc self.awrite = self.awrite_pc self.is_closing = self.is_closing_pc async def readline(self): """ The firt time, this method completely reads the stream. It then returns only the requested row. This significantly increases read performance. """ pos = self.buffer.find(b"\r\n") if pos == -1: self.buffer += await self.reader.read(1440) pos = self.buffer.find(b"\r\n") if pos == -1: result = self.buffer self.buffer = b"" else: result = self.buffer[:pos+2] self.buffer = self.buffer[pos+2:] return result async def read(self, length): """ Read data from the stream """ if len(self.buffer) < length: data = await self.reader.read(length - len(self.buffer)) self.buffer += data data = self.buffer[:length] self.buffer = self.buffer[length:] if Stream.trace: Stream.trace.write(b"\n# read\n") Stream.trace.write(data) Stream.trace.flush() return data async def write(self, data): """ Write data in the stream """ result = await self.awrite(data) if self.is_closing(): raise OSError(104,"Closed connection") if Stream.trace: Stream.trace.write(b"\n# write\n") Stream.trace.write(data) Stream.trace.flush() if result is None: result = len(data) else: result = -1 return result async def awrite_mcp(self, data): """ Awrite micropython """ return await self.writer.awrite(data) async def awrite_pc(self, data): """ Awrite micropython """ return self.writer.write(data) async def close_mcp(self): """ Close the stream """ await self.writer.aclose() async def close_pc(self): """ Close the stream """ self.writer.close() def is_closing_pc(self): """ Check if it closed """ return self.writer.is_closing() def is_closing_mcp(self): """ Check if it closed """ return FalseClass variables
var trace
Methods
async def awrite_mcp(self, data)-
Awrite micropython
Expand source code
async def awrite_mcp(self, data): """ Awrite micropython """ return await self.writer.awrite(data) async def awrite_pc(self, data)-
Awrite micropython
Expand source code
async def awrite_pc(self, data): """ Awrite micropython """ return self.writer.write(data) async def close_mcp(self)-
Close the stream
Expand source code
async def close_mcp(self): """ Close the stream """ await self.writer.aclose() async def close_pc(self)-
Close the stream
Expand source code
async def close_pc(self): """ Close the stream """ self.writer.close() def is_closing_mcp(self)-
Check if it closed
Expand source code
def is_closing_mcp(self): """ Check if it closed """ return False def is_closing_pc(self)-
Check if it closed
Expand source code
def is_closing_pc(self): """ Check if it closed """ return self.writer.is_closing() async def read(self, length)-
Read data from the stream
Expand source code
async def read(self, length): """ Read data from the stream """ if len(self.buffer) < length: data = await self.reader.read(length - len(self.buffer)) self.buffer += data data = self.buffer[:length] self.buffer = self.buffer[length:] if Stream.trace: Stream.trace.write(b"\n# read\n") Stream.trace.write(data) Stream.trace.flush() return data async def readline(self)-
The firt time, this method completely reads the stream. It then returns only the requested row. This significantly increases read performance.
Expand source code
async def readline(self): """ The firt time, this method completely reads the stream. It then returns only the requested row. This significantly increases read performance. """ pos = self.buffer.find(b"\r\n") if pos == -1: self.buffer += await self.reader.read(1440) pos = self.buffer.find(b"\r\n") if pos == -1: result = self.buffer self.buffer = b"" else: result = self.buffer[:pos+2] self.buffer = self.buffer[pos+2:] return result async def write(self, data)-
Write data in the stream
Expand source code
async def write(self, data): """ Write data in the stream """ result = await self.awrite(data) if self.is_closing(): raise OSError(104,"Closed connection") if Stream.trace: Stream.trace.write(b"\n# write\n") Stream.trace.write(data) Stream.trace.flush() if result is None: result = len(data) else: result = -1 return result