mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
moved AioExclusiveRegion to aiotools
This commit is contained in:
parent
5ef5e00da9
commit
75d9b858d7
@ -1,55 +0,0 @@
|
|||||||
# ========================================================================== #
|
|
||||||
# #
|
|
||||||
# KVMD - The main Pi-KVM daemon. #
|
|
||||||
# #
|
|
||||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
|
||||||
# #
|
|
||||||
# This program is free software: you can redistribute it and/or modify #
|
|
||||||
# it under the terms of the GNU General Public License as published by #
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or #
|
|
||||||
# (at your option) any later version. #
|
|
||||||
# #
|
|
||||||
# This program is distributed in the hope that it will be useful, #
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
||||||
# GNU General Public License for more details. #
|
|
||||||
# #
|
|
||||||
# You should have received a copy of the GNU General Public License #
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
|
||||||
# #
|
|
||||||
# ========================================================================== #
|
|
||||||
|
|
||||||
|
|
||||||
import types
|
|
||||||
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
|
|
||||||
# =====
|
|
||||||
class AioExclusiveRegion:
|
|
||||||
def __init__(self, exc_type: Type[Exception]) -> None:
|
|
||||||
self.__exc_type = exc_type
|
|
||||||
self.__busy = False
|
|
||||||
|
|
||||||
def is_busy(self) -> bool:
|
|
||||||
return self.__busy
|
|
||||||
|
|
||||||
def enter(self) -> None:
|
|
||||||
if not self.__busy:
|
|
||||||
self.__busy = True
|
|
||||||
return
|
|
||||||
raise self.__exc_type()
|
|
||||||
|
|
||||||
def exit(self) -> None:
|
|
||||||
self.__busy = False
|
|
||||||
|
|
||||||
def __enter__(self) -> None:
|
|
||||||
self.enter()
|
|
||||||
|
|
||||||
def __exit__(
|
|
||||||
self,
|
|
||||||
_exc_type: Type[BaseException],
|
|
||||||
_exc: BaseException,
|
|
||||||
_tb: types.TracebackType,
|
|
||||||
) -> None:
|
|
||||||
self.exit()
|
|
||||||
@ -24,6 +24,7 @@ import os
|
|||||||
import asyncio
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import types
|
||||||
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
@ -32,14 +33,13 @@ from typing import Callable
|
|||||||
from typing import Coroutine
|
from typing import Coroutine
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
from typing import Type
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import aiofiles.base
|
import aiofiles.base
|
||||||
|
|
||||||
from . import aioregion
|
|
||||||
|
|
||||||
from .logging import get_logger
|
from .logging import get_logger
|
||||||
|
|
||||||
|
|
||||||
@ -104,16 +104,6 @@ def run_sync(coro: Coroutine[Any, Any, _RetvalT]) -> _RetvalT:
|
|||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
@contextlib.contextmanager
|
|
||||||
def unregion_only_on_exception(region: aioregion.AioExclusiveRegion) -> Generator[None, None, None]:
|
|
||||||
region.enter()
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except: # noqa: E722
|
|
||||||
region.exit()
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.asynccontextmanager
|
@contextlib.asynccontextmanager
|
||||||
async def unlock_only_on_exception(lock: asyncio.Lock) -> AsyncGenerator[None, None]:
|
async def unlock_only_on_exception(lock: asyncio.Lock) -> AsyncGenerator[None, None]:
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
@ -129,3 +119,42 @@ async def afile_write_now(afile: aiofiles.base.AiofilesContextManager, data: byt
|
|||||||
await afile.write(data)
|
await afile.write(data)
|
||||||
await afile.flush()
|
await afile.flush()
|
||||||
await run_async(os.fsync, afile.fileno())
|
await run_async(os.fsync, afile.fileno())
|
||||||
|
|
||||||
|
|
||||||
|
# =====
|
||||||
|
class AioExclusiveRegion:
|
||||||
|
def __init__(self, exc_type: Type[Exception]) -> None:
|
||||||
|
self.__exc_type = exc_type
|
||||||
|
self.__busy = False
|
||||||
|
|
||||||
|
def is_busy(self) -> bool:
|
||||||
|
return self.__busy
|
||||||
|
|
||||||
|
def enter(self) -> None:
|
||||||
|
if not self.__busy:
|
||||||
|
self.__busy = True
|
||||||
|
return
|
||||||
|
raise self.__exc_type()
|
||||||
|
|
||||||
|
def exit(self) -> None:
|
||||||
|
self.__busy = False
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exit_only_on_exception(self) -> Generator[None, None, None]:
|
||||||
|
self.enter()
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except: # noqa: E722
|
||||||
|
self.exit()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def __enter__(self) -> None:
|
||||||
|
self.enter()
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self,
|
||||||
|
_exc_type: Type[BaseException],
|
||||||
|
_exc: BaseException,
|
||||||
|
_tb: types.TracebackType,
|
||||||
|
) -> None:
|
||||||
|
self.exit()
|
||||||
|
|||||||
@ -29,7 +29,6 @@ from typing import AsyncGenerator
|
|||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
from ... import aioregion
|
|
||||||
from ... import gpio
|
from ... import gpio
|
||||||
|
|
||||||
from ...yamlconf import Option
|
from ...yamlconf import Option
|
||||||
@ -75,7 +74,7 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
self.__state_poll = state_poll
|
self.__state_poll = state_poll
|
||||||
|
|
||||||
self.__region = aioregion.AioExclusiveRegion(AtxIsBusyError)
|
self.__region = aiotools.AioExclusiveRegion(AtxIsBusyError)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_plugin_options(cls) -> Dict:
|
def get_plugin_options(cls) -> Dict:
|
||||||
@ -163,7 +162,7 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
@aiotools.atomic
|
@aiotools.atomic
|
||||||
async def __click(self, name: str, pin: int, delay: float) -> None:
|
async def __click(self, name: str, pin: int, delay: float) -> None:
|
||||||
with aiotools.unregion_only_on_exception(self.__region):
|
with self.__region.exit_only_on_exception():
|
||||||
await self.__inner_click(name, pin, delay)
|
await self.__inner_click(name, pin, delay)
|
||||||
|
|
||||||
@aiotools.tasked
|
@aiotools.tasked
|
||||||
|
|||||||
@ -45,7 +45,6 @@ from ....validators.os import valid_abs_dir
|
|||||||
from ....validators.os import valid_command
|
from ....validators.os import valid_command
|
||||||
|
|
||||||
from .... import aiotools
|
from .... import aiotools
|
||||||
from .... import aioregion
|
|
||||||
|
|
||||||
from .. import MsdError
|
from .. import MsdError
|
||||||
from .. import MsdIsBusyError
|
from .. import MsdIsBusyError
|
||||||
@ -111,7 +110,7 @@ class _State:
|
|||||||
self.vd: Optional[_VirtualDriveState] = None
|
self.vd: Optional[_VirtualDriveState] = None
|
||||||
|
|
||||||
self._lock = asyncio.Lock()
|
self._lock = asyncio.Lock()
|
||||||
self._region = aioregion.AioExclusiveRegion(MsdIsBusyError)
|
self._region = aiotools.AioExclusiveRegion(MsdIsBusyError)
|
||||||
|
|
||||||
@contextlib.asynccontextmanager
|
@contextlib.asynccontextmanager
|
||||||
async def busy(self, check_online: bool=True) -> AsyncGenerator[None, None]:
|
async def busy(self, check_online: bool=True) -> AsyncGenerator[None, None]:
|
||||||
|
|||||||
@ -40,7 +40,6 @@ import aiofiles.base
|
|||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
from ... import aioregion
|
|
||||||
from ... import gpio
|
from ... import gpio
|
||||||
|
|
||||||
from ...yamlconf import Option
|
from ...yamlconf import Option
|
||||||
@ -174,7 +173,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
|||||||
self.__init_retries = init_retries
|
self.__init_retries = init_retries
|
||||||
self.__reset_delay = reset_delay
|
self.__reset_delay = reset_delay
|
||||||
|
|
||||||
self.__region = aioregion.AioExclusiveRegion(MsdIsBusyError)
|
self.__region = aiotools.AioExclusiveRegion(MsdIsBusyError)
|
||||||
|
|
||||||
self.__device_info: Optional[_DeviceInfo] = None
|
self.__device_info: Optional[_DeviceInfo] = None
|
||||||
self.__connected = False
|
self.__connected = False
|
||||||
@ -235,7 +234,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
@aiotools.atomic
|
@aiotools.atomic
|
||||||
async def reset(self) -> None:
|
async def reset(self) -> None:
|
||||||
with aiotools.unregion_only_on_exception(self.__region):
|
with self.__region.exit_only_on_exception():
|
||||||
await self.__inner_reset()
|
await self.__inner_reset()
|
||||||
|
|
||||||
@aiotools.tasked
|
@aiotools.tasked
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import asyncio
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from kvmd.aioregion import AioExclusiveRegion
|
from kvmd.aiotools import AioExclusiveRegion
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
@ -34,7 +34,7 @@ class RegionIsBusyError(Exception):
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_ok__access_one() -> None:
|
async def test_ok__region__access_one() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func() -> None:
|
async def func() -> None:
|
||||||
@ -51,7 +51,7 @@ async def test_ok__access_one() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_fail__access_one() -> None:
|
async def test_fail__region__access_one() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func() -> None:
|
async def func() -> None:
|
||||||
@ -71,7 +71,7 @@ async def test_fail__access_one() -> None:
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_ok__access_two() -> None:
|
async def test_ok__region__access_two() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func1() -> None:
|
async def func1() -> None:
|
||||||
@ -94,7 +94,7 @@ async def test_ok__access_two() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_fail__access_two() -> None:
|
async def test_fail__region__access_two() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func1() -> None:
|
async def func1() -> None:
|
||||||
Loading…
x
Reference in New Issue
Block a user