moved AioExclusiveRegion to aiotools

This commit is contained in:
Devaev Maxim 2020-02-29 17:23:57 +03:00
parent 5ef5e00da9
commit 75d9b858d7
6 changed files with 51 additions and 80 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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]:

View File

@ -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

View File

@ -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: