mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 17:20:30 +08:00
global event loop
This commit is contained in:
parent
a6028c46a4
commit
60849efa72
@ -20,8 +20,6 @@
|
|||||||
# ========================================================================== #
|
# ========================================================================== #
|
||||||
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -46,7 +44,6 @@ def main(argv: Optional[List[str]]=None) -> None:
|
|||||||
config = init("kvmd", description="The main Pi-KVM daemon", argv=argv)[2].kvmd
|
config = init("kvmd", description="The main Pi-KVM daemon", argv=argv)[2].kvmd
|
||||||
with gpio.bcm():
|
with gpio.bcm():
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
Server(
|
Server(
|
||||||
auth_manager=AuthManager(
|
auth_manager=AuthManager(
|
||||||
internal_users=config.auth.internal_users,
|
internal_users=config.auth.internal_users,
|
||||||
@ -55,14 +52,12 @@ def main(argv: Optional[List[str]]=None) -> None:
|
|||||||
internal=config.auth.internal._unpack(),
|
internal=config.auth.internal._unpack(),
|
||||||
external=(config.auth.external._unpack() if config.auth.external_type else {}),
|
external=(config.auth.external._unpack() if config.auth.external_type else {}),
|
||||||
),
|
),
|
||||||
info_manager=InfoManager(loop=loop, **config.info._unpack()),
|
info_manager=InfoManager(**config.info._unpack()),
|
||||||
log_reader=LogReader(loop=loop),
|
log_reader=LogReader(),
|
||||||
|
|
||||||
hid=Hid(**config.hid._unpack()),
|
hid=Hid(**config.hid._unpack()),
|
||||||
atx=Atx(**config.atx._unpack()),
|
atx=Atx(**config.atx._unpack()),
|
||||||
msd=MassStorageDevice(loop=loop, **config.msd._unpack()),
|
msd=MassStorageDevice(**config.msd._unpack()),
|
||||||
streamer=Streamer(loop=loop, **config.streamer._unpack()),
|
streamer=Streamer(**config.streamer._unpack()),
|
||||||
|
|
||||||
loop=loop,
|
|
||||||
).run(**config.server._unpack())
|
).run(**config.server._unpack())
|
||||||
get_logger().info("Bye-bye")
|
get_logger().info("Bye-bye")
|
||||||
|
|||||||
@ -37,19 +37,16 @@ class InfoManager:
|
|||||||
self,
|
self,
|
||||||
meta_path: str,
|
meta_path: str,
|
||||||
extras_path: str,
|
extras_path: str,
|
||||||
loop: asyncio.AbstractEventLoop,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.__meta_path = meta_path
|
self.__meta_path = meta_path
|
||||||
self.__extras_path = extras_path
|
self.__extras_path = extras_path
|
||||||
|
|
||||||
self.__loop = loop
|
|
||||||
|
|
||||||
async def get_meta(self) -> Dict:
|
async def get_meta(self) -> Dict:
|
||||||
return (await self.__loop.run_in_executor(None, load_yaml_file, self.__meta_path))
|
return (await asyncio.get_running_loop().run_in_executor(None, load_yaml_file, self.__meta_path))
|
||||||
|
|
||||||
async def get_extras(self) -> Dict:
|
async def get_extras(self) -> Dict:
|
||||||
return (await self.__loop.run_in_executor(None, self.__sync_get_extras))
|
return (await asyncio.get_running_loop().run_in_executor(None, self.__sync_get_extras))
|
||||||
|
|
||||||
def __sync_get_extras(self) -> Dict:
|
def __sync_get_extras(self) -> Dict:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -32,9 +32,6 @@ import systemd.journal
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
class LogReader:
|
class LogReader:
|
||||||
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
||||||
self.__loop = loop
|
|
||||||
|
|
||||||
async def poll_log(self, seek: int, follow: bool) -> AsyncGenerator[Dict, None]:
|
async def poll_log(self, seek: int, follow: bool) -> AsyncGenerator[Dict, None]:
|
||||||
reader = systemd.journal.Reader()
|
reader = systemd.journal.Reader()
|
||||||
reader.this_boot()
|
reader.this_boot()
|
||||||
|
|||||||
@ -206,8 +206,6 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes
|
|||||||
reset_delay: float,
|
reset_delay: float,
|
||||||
write_meta: bool,
|
write_meta: bool,
|
||||||
chunk_size: int,
|
chunk_size: int,
|
||||||
|
|
||||||
loop: asyncio.AbstractEventLoop,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
@ -226,8 +224,6 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes
|
|||||||
self.__write_meta = write_meta
|
self.__write_meta = write_meta
|
||||||
self.chunk_size = chunk_size
|
self.chunk_size = chunk_size
|
||||||
|
|
||||||
self.__loop = loop
|
|
||||||
|
|
||||||
self.__device_info: Optional[_MassStorageDeviceInfo] = None
|
self.__device_info: Optional[_MassStorageDeviceInfo] = None
|
||||||
self.__saved_device_info: Optional[_MassStorageDeviceInfo] = None
|
self.__saved_device_info: Optional[_MassStorageDeviceInfo] = None
|
||||||
self.__region = aioregion.AioExclusiveRegion(MsdIsBusyError)
|
self.__region = aioregion.AioExclusiveRegion(MsdIsBusyError)
|
||||||
@ -241,7 +237,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes
|
|||||||
logger.info("Using %r as mass-storage device", self._device_path)
|
logger.info("Using %r as mass-storage device", self._device_path)
|
||||||
try:
|
try:
|
||||||
logger.info("Enabled image metadata writing")
|
logger.info("Enabled image metadata writing")
|
||||||
loop.run_until_complete(self.connect_to_kvm(no_delay=True))
|
asyncio.get_event_loop().run_until_complete(self.connect_to_kvm(no_delay=True))
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
if isinstance(err, MsdError):
|
if isinstance(err, MsdError):
|
||||||
log = logger.error
|
log = logger.error
|
||||||
@ -366,10 +362,10 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes
|
|||||||
assert self.__device_file
|
assert self.__device_file
|
||||||
await self.__device_file.write(data)
|
await self.__device_file.write(data)
|
||||||
await self.__device_file.flush()
|
await self.__device_file.flush()
|
||||||
await self.__loop.run_in_executor(None, os.fsync, self.__device_file.fileno())
|
await asyncio.get_running_loop().run_in_executor(None, os.fsync, self.__device_file.fileno())
|
||||||
|
|
||||||
async def __load_device_info(self) -> None:
|
async def __load_device_info(self) -> None:
|
||||||
device_info = await self.__loop.run_in_executor(None, _explore_device, self._device_path)
|
device_info = await asyncio.get_running_loop().run_in_executor(None, _explore_device, self._device_path)
|
||||||
if not device_info:
|
if not device_info:
|
||||||
raise MsdError("Can't explore device %r" % (self._device_path))
|
raise MsdError("Can't explore device %r" % (self._device_path))
|
||||||
self.__device_info = self.__saved_device_info = device_info
|
self.__device_info = self.__saved_device_info = device_info
|
||||||
|
|||||||
@ -217,8 +217,6 @@ class Server: # pylint: disable=too-many-instance-attributes
|
|||||||
atx: Atx,
|
atx: Atx,
|
||||||
msd: MassStorageDevice,
|
msd: MassStorageDevice,
|
||||||
streamer: Streamer,
|
streamer: Streamer,
|
||||||
|
|
||||||
loop: asyncio.AbstractEventLoop,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self._auth_manager = auth_manager
|
self._auth_manager = auth_manager
|
||||||
@ -230,8 +228,6 @@ class Server: # pylint: disable=too-many-instance-attributes
|
|||||||
self.__msd = msd
|
self.__msd = msd
|
||||||
self.__streamer = streamer
|
self.__streamer = streamer
|
||||||
|
|
||||||
self.__loop = loop
|
|
||||||
|
|
||||||
self.__heartbeat: Optional[float] = None # Assigned in run() for consistance
|
self.__heartbeat: Optional[float] = None # Assigned in run() for consistance
|
||||||
self.__sockets: Set[aiohttp.web.WebSocketResponse] = set()
|
self.__sockets: Set[aiohttp.web.WebSocketResponse] = set()
|
||||||
self.__sockets_lock = asyncio.Lock()
|
self.__sockets_lock = asyncio.Lock()
|
||||||
@ -257,23 +253,6 @@ class Server: # pylint: disable=too-many-instance-attributes
|
|||||||
setproctitle.setproctitle("[main] " + setproctitle.getproctitle())
|
setproctitle.setproctitle("[main] " + setproctitle.getproctitle())
|
||||||
|
|
||||||
self.__heartbeat = heartbeat
|
self.__heartbeat = heartbeat
|
||||||
app = aiohttp.web.Application(loop=self.__loop)
|
|
||||||
app.on_shutdown.append(self.__on_shutdown)
|
|
||||||
app.on_cleanup.append(self.__on_cleanup)
|
|
||||||
|
|
||||||
for name in dir(self):
|
|
||||||
method = getattr(self, name)
|
|
||||||
if inspect.ismethod(method):
|
|
||||||
if getattr(method, _ATTR_SYSTEM_TASK, False):
|
|
||||||
self.__system_tasks.append(self.__loop.create_task(method()))
|
|
||||||
elif getattr(method, _ATTR_EXPOSED, False):
|
|
||||||
# router = app.router
|
|
||||||
router = getattr(app, "router") # FIXME: Dirty hack to avoid pylint crash
|
|
||||||
router.add_route(
|
|
||||||
getattr(method, _ATTR_EXPOSED_METHOD),
|
|
||||||
getattr(method, _ATTR_EXPOSED_PATH),
|
|
||||||
method,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert port or unix_path
|
assert port or unix_path
|
||||||
if unix_path:
|
if unix_path:
|
||||||
@ -289,7 +268,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
|||||||
socket_kwargs = {"host": host, "port": port}
|
socket_kwargs = {"host": host, "port": port}
|
||||||
|
|
||||||
aiohttp.web.run_app(
|
aiohttp.web.run_app(
|
||||||
app=app,
|
app=self.__make_app(),
|
||||||
access_log_format=access_log_format,
|
access_log_format=access_log_format,
|
||||||
print=self.__run_app_print,
|
print=self.__run_app_print,
|
||||||
**socket_kwargs,
|
**socket_kwargs,
|
||||||
@ -513,7 +492,27 @@ class Server: # pylint: disable=too-many-instance-attributes
|
|||||||
self.__reset_streamer = True
|
self.__reset_streamer = True
|
||||||
return _json()
|
return _json()
|
||||||
|
|
||||||
# =====
|
# ===== SYSTEM STUFF
|
||||||
|
|
||||||
|
async def __make_app(self) -> aiohttp.web.Application:
|
||||||
|
app = aiohttp.web.Application()
|
||||||
|
app.on_shutdown.append(self.__on_shutdown)
|
||||||
|
app.on_cleanup.append(self.__on_cleanup)
|
||||||
|
|
||||||
|
for name in dir(self):
|
||||||
|
method = getattr(self, name)
|
||||||
|
if inspect.ismethod(method):
|
||||||
|
if getattr(method, _ATTR_SYSTEM_TASK, False):
|
||||||
|
self.__system_tasks.append(asyncio.create_task(method()))
|
||||||
|
elif getattr(method, _ATTR_EXPOSED, False):
|
||||||
|
# router = app.router
|
||||||
|
router = getattr(app, "router") # FIXME: Dirty hack to avoid pylint crash
|
||||||
|
router.add_route(
|
||||||
|
getattr(method, _ATTR_EXPOSED_METHOD),
|
||||||
|
getattr(method, _ATTR_EXPOSED_PATH),
|
||||||
|
method,
|
||||||
|
)
|
||||||
|
return app
|
||||||
|
|
||||||
def __run_app_print(self, text: str) -> None:
|
def __run_app_print(self, text: str) -> None:
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|||||||
@ -61,8 +61,6 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
timeout: float,
|
timeout: float,
|
||||||
|
|
||||||
cmd: List[str],
|
cmd: List[str],
|
||||||
|
|
||||||
loop: asyncio.AbstractEventLoop,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.__cap_pin = (gpio.set_output(cap_pin) if cap_pin >= 0 else -1)
|
self.__cap_pin = (gpio.set_output(cap_pin) if cap_pin >= 0 else -1)
|
||||||
@ -87,8 +85,6 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
self.__cmd = cmd
|
self.__cmd = cmd
|
||||||
|
|
||||||
self.__loop = loop
|
|
||||||
|
|
||||||
self.__streamer_task: Optional[asyncio.Task] = None
|
self.__streamer_task: Optional[asyncio.Task] = None
|
||||||
|
|
||||||
self.__http_session: Optional[aiohttp.ClientSession] = None
|
self.__http_session: Optional[aiohttp.ClientSession] = None
|
||||||
@ -174,7 +170,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
async def __inner_start(self) -> None:
|
async def __inner_start(self) -> None:
|
||||||
assert not self.__streamer_task
|
assert not self.__streamer_task
|
||||||
await self.__set_hw_enabled(True)
|
await self.__set_hw_enabled(True)
|
||||||
self.__streamer_task = self.__loop.create_task(self.__run_streamer())
|
self.__streamer_task = asyncio.get_running_loop().create_task(self.__run_streamer())
|
||||||
|
|
||||||
async def __inner_stop(self) -> None:
|
async def __inner_stop(self) -> None:
|
||||||
assert self.__streamer_task
|
assert self.__streamer_task
|
||||||
|
|||||||
@ -30,8 +30,7 @@ from kvmd.aioregion import AioExclusiveRegion
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_ok__access_one(event_loop: asyncio.AbstractEventLoop) -> None:
|
async def test_ok__access_one() -> None:
|
||||||
_ = event_loop
|
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func() -> None:
|
async def func() -> None:
|
||||||
@ -48,8 +47,7 @@ async def test_ok__access_one(event_loop: asyncio.AbstractEventLoop) -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_fail__access_one(event_loop: asyncio.AbstractEventLoop) -> None:
|
async def test_fail__access_one() -> None:
|
||||||
_ = event_loop
|
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func() -> None:
|
async def func() -> None:
|
||||||
@ -69,19 +67,19 @@ async def test_fail__access_one(event_loop: asyncio.AbstractEventLoop) -> None:
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_ok__access_two(event_loop: asyncio.AbstractEventLoop) -> None:
|
async def test_ok__access_two() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func1() -> None:
|
async def func1() -> None:
|
||||||
with region:
|
with region:
|
||||||
await asyncio.sleep(1, loop=event_loop)
|
await asyncio.sleep(1)
|
||||||
print("done func1()")
|
print("done func1()")
|
||||||
|
|
||||||
async def func2() -> None:
|
async def func2() -> None:
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
print("waiking up func2()")
|
print("waiking up func2()")
|
||||||
with region:
|
with region:
|
||||||
await asyncio.sleep(1, loop=event_loop)
|
await asyncio.sleep(1)
|
||||||
print("done func2()")
|
print("done func2()")
|
||||||
|
|
||||||
await asyncio.gather(func1(), func2())
|
await asyncio.gather(func1(), func2())
|
||||||
@ -92,21 +90,21 @@ async def test_ok__access_two(event_loop: asyncio.AbstractEventLoop) -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_fail__access_two(event_loop: asyncio.AbstractEventLoop) -> None:
|
async def test_fail__access_two() -> None:
|
||||||
region = AioExclusiveRegion(RegionIsBusyError)
|
region = AioExclusiveRegion(RegionIsBusyError)
|
||||||
|
|
||||||
async def func1() -> None:
|
async def func1() -> None:
|
||||||
with region:
|
with region:
|
||||||
await asyncio.sleep(2, loop=event_loop)
|
await asyncio.sleep(2)
|
||||||
print("done func1()")
|
print("done func1()")
|
||||||
|
|
||||||
async def func2() -> None:
|
async def func2() -> None:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
with region:
|
with region:
|
||||||
await asyncio.sleep(1, loop=event_loop)
|
await asyncio.sleep(1)
|
||||||
print("done func2()")
|
print("done func2()")
|
||||||
|
|
||||||
results = await asyncio.gather(func1(), func2(), loop=event_loop, return_exceptions=True)
|
results = await asyncio.gather(func1(), func2(), return_exceptions=True)
|
||||||
assert results[0] is None
|
assert results[0] is None
|
||||||
assert type(results[1]) == RegionIsBusyError # pylint: disable=unidiomatic-typecheck
|
assert type(results[1]) == RegionIsBusyError # pylint: disable=unidiomatic-typecheck
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user