mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 09:01:54 +08:00
reading images api
This commit is contained in:
@@ -131,6 +131,15 @@ class BaseMsd(BasePlugin):
|
||||
async def set_connected(self, connected: bool) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def read_image(self, name: str) -> AsyncGenerator[int, None]: # pylint: disable=unused-argument
|
||||
if self is not None: # XXX: Vulture and pylint hack
|
||||
raise NotImplementedError()
|
||||
yield 1
|
||||
|
||||
async def read_image_chunk(self) -> bytes:
|
||||
raise NotImplementedError()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def write_image(self, name: str, size: int) -> AsyncGenerator[int, None]: # pylint: disable=unused-argument
|
||||
if self is not None: # XXX: Vulture and pylint hack
|
||||
@@ -144,6 +153,40 @@ class BaseMsd(BasePlugin):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class MsdImageReader:
|
||||
def __init__(self, path: str, chunk_size: int) -> None:
|
||||
self.__name = os.path.basename(path)
|
||||
self.__path = path
|
||||
self.__chunk_size = chunk_size
|
||||
|
||||
self.__file: Optional[aiofiles.base.AiofilesContextManager] = None
|
||||
self.__file_size: int = 0
|
||||
|
||||
async def open(self) -> "MsdImageReader":
|
||||
assert self.__file is None
|
||||
get_logger(1).info("Reading %r image from MSD ...", self.__name)
|
||||
self.__file_size = os.stat(self.__path).st_size
|
||||
self.__file = await aiofiles.open(self.__path, mode="rb") # type: ignore
|
||||
return self
|
||||
|
||||
def get_size(self) -> int:
|
||||
assert self.__file is not None
|
||||
return self.__file_size
|
||||
|
||||
async def read(self) -> bytes:
|
||||
assert self.__file is not None
|
||||
return (await self.__file.read(self.__chunk_size)) # type: ignore
|
||||
|
||||
async def close(self) -> None:
|
||||
assert self.__file is not None
|
||||
logger = get_logger()
|
||||
logger.info("Closed image reader ...")
|
||||
try:
|
||||
await self.__file.close() # type: ignore
|
||||
except Exception:
|
||||
logger.exception("Can't close image reader")
|
||||
|
||||
|
||||
class MsdImageWriter:
|
||||
def __init__(self, path: str, size: int, sync: int) -> None:
|
||||
self.__name = os.path.basename(path)
|
||||
|
||||
@@ -76,6 +76,15 @@ class Plugin(BaseMsd):
|
||||
async def set_connected(self, connected: bool) -> None:
|
||||
raise MsdDisabledError()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def read_image(self, name: str) -> AsyncGenerator[int, None]:
|
||||
if self is not None: # XXX: Vulture and pylint hack
|
||||
raise MsdDisabledError()
|
||||
yield 1
|
||||
|
||||
async def read_image_chunk(self) -> bytes:
|
||||
raise MsdDisabledError()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def write_image(self, name: str, size: int) -> AsyncGenerator[int, None]:
|
||||
if self is not None: # XXX: Vulture and pylint hack
|
||||
|
||||
@@ -57,6 +57,7 @@ from .. import MsdImageNotSelected
|
||||
from .. import MsdUnknownImageError
|
||||
from .. import MsdImageExistsError
|
||||
from .. import BaseMsd
|
||||
from .. import MsdImageReader
|
||||
from .. import MsdImageWriter
|
||||
|
||||
from . import fs
|
||||
@@ -136,6 +137,7 @@ class _State:
|
||||
class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
def __init__( # pylint: disable=super-init-not-called
|
||||
self,
|
||||
read_chunk_size: int,
|
||||
write_chunk_size: int,
|
||||
sync_chunk_size: int,
|
||||
|
||||
@@ -148,6 +150,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
gadget: str, # XXX: Not from options, see /kvmd/apps/kvmd/__init__.py for details
|
||||
) -> None:
|
||||
|
||||
self.__read_chunk_size = read_chunk_size
|
||||
self.__write_chunk_size = write_chunk_size
|
||||
self.__sync_chunk_size = sync_chunk_size
|
||||
|
||||
@@ -162,6 +165,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
self.__drive = Drive(gadget, instance=0, lun=0)
|
||||
|
||||
self.__reader: Optional[MsdImageReader] = None
|
||||
self.__writer: Optional[MsdImageWriter] = None
|
||||
self.__writer_tick = 0.0
|
||||
|
||||
@@ -175,6 +179,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
@classmethod
|
||||
def get_plugin_options(cls) -> Dict:
|
||||
return {
|
||||
"read_chunk_size": Option(65536, type=functools.partial(valid_number, min=1024)),
|
||||
"write_chunk_size": Option(65536, type=functools.partial(valid_number, min=1024)),
|
||||
"sync_chunk_size": Option(4194304, type=functools.partial(valid_number, min=1024)),
|
||||
|
||||
@@ -253,6 +258,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
@aiotools.atomic
|
||||
async def cleanup(self) -> None:
|
||||
await self.__close_reader()
|
||||
await self.__close_writer()
|
||||
|
||||
# =====
|
||||
@@ -317,6 +323,29 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
self.__state.vd.connected = connected
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def read_image(self, name: str) -> AsyncGenerator[int, None]:
|
||||
async with self.__state.busy():
|
||||
assert self.__state.storage
|
||||
assert self.__state.vd
|
||||
|
||||
if self.__state.vd.connected or self.__drive.get_image_path():
|
||||
raise MsdConnectedError()
|
||||
|
||||
path = os.path.join(self.__images_path, name)
|
||||
if name not in self.__state.storage.images or not os.path.exists(path):
|
||||
raise MsdUnknownImageError()
|
||||
|
||||
try:
|
||||
self.__reader = await MsdImageReader(path, self.__read_chunk_size).open()
|
||||
yield self.__reader.get_size()
|
||||
finally:
|
||||
await self.__close_reader()
|
||||
|
||||
async def read_image_chunk(self) -> bytes:
|
||||
assert self.__reader
|
||||
return (await self.__reader.read())
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def write_image(self, name: str, size: int) -> AsyncGenerator[int, None]:
|
||||
try:
|
||||
@@ -387,6 +416,11 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
# =====
|
||||
|
||||
async def __close_reader(self) -> None:
|
||||
if self.__reader:
|
||||
await self.__reader.close()
|
||||
self.__reader = None
|
||||
|
||||
async def __close_writer(self) -> None:
|
||||
if self.__writer:
|
||||
await self.__writer.close()
|
||||
|
||||
@@ -217,6 +217,17 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
||||
get_logger(0).info("MSD switched to KVM: %s", self.__device_info)
|
||||
self.__connected = connected
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def read_image(self, name: str) -> AsyncGenerator[int, None]:
|
||||
async with self.__working():
|
||||
if self is not None: # XXX: Vulture and pylint hack
|
||||
raise MsdMultiNotSupported()
|
||||
yield 1
|
||||
|
||||
async def read_image_chunk(self) -> bytes:
|
||||
async with self.__working():
|
||||
raise MsdMultiNotSupported()
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def write_image(self, name: str, size: int) -> AsyncGenerator[int, None]:
|
||||
async with self.__working():
|
||||
|
||||
Reference in New Issue
Block a user