mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-02-02 19:11:54 +08:00
periodic snapshots
This commit is contained in:
130
kvmd/apps/kvmd/snapshoter.py
Normal file
130
kvmd/apps/kvmd/snapshoter.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# ========================================================================== #
|
||||
# #
|
||||
# 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 asyncio
|
||||
import time
|
||||
|
||||
from typing import Callable
|
||||
|
||||
from ...logging import get_logger
|
||||
|
||||
from ...plugins.hid import BaseHid
|
||||
|
||||
from ... import aiotools
|
||||
|
||||
from .streamer import Streamer
|
||||
|
||||
|
||||
# =====
|
||||
class Snapshoter: # pylint: disable=too-many-instance-attributes
|
||||
def __init__(
|
||||
self,
|
||||
hid: BaseHid,
|
||||
streamer: Streamer,
|
||||
|
||||
idle_interval: float,
|
||||
live_interval: float,
|
||||
|
||||
wakeup_key: str,
|
||||
wakeup_move: int,
|
||||
|
||||
online_delay: float,
|
||||
retries: int,
|
||||
retries_delay: float,
|
||||
) -> None:
|
||||
|
||||
self.__hid = hid
|
||||
self.__streamer = streamer
|
||||
|
||||
if idle_interval or live_interval:
|
||||
self.__idle_interval = (idle_interval or live_interval)
|
||||
self.__live_interval = (live_interval or idle_interval)
|
||||
assert self.__idle_interval
|
||||
assert self.__live_interval
|
||||
else:
|
||||
self.__idle_interval = self.__live_interval = 0.0
|
||||
|
||||
self.__wakeup_key = wakeup_key
|
||||
self.__wakeup_move = wakeup_move
|
||||
|
||||
self.__online_delay = online_delay
|
||||
self.__retries = retries
|
||||
self.__retries_delay = retries_delay
|
||||
|
||||
self.__snapshoting = False
|
||||
|
||||
async def run(self, is_live: Callable[[], bool], notifier: aiotools.AioNotifier) -> None:
|
||||
if self.__idle_interval or self.__live_interval:
|
||||
get_logger(0).info("Running periodic stream snapshot: idle=%.2f; live=%.2f ...",
|
||||
self.__idle_interval, self.__live_interval)
|
||||
|
||||
last_snapshot_ts = 0.0
|
||||
while True:
|
||||
live = is_live()
|
||||
if last_snapshot_ts + (self.__live_interval if live else self.__idle_interval) < time.time():
|
||||
await self.__make_snapshot(live, notifier)
|
||||
last_snapshot_ts = time.time()
|
||||
await asyncio.sleep(min(self.__idle_interval, self.__live_interval))
|
||||
else:
|
||||
await aiotools.wait_infinite()
|
||||
|
||||
def snapshoting(self) -> bool:
|
||||
return self.__snapshoting
|
||||
|
||||
async def __make_snapshot(self, live: bool, notifier: aiotools.AioNotifier) -> None:
|
||||
logger = get_logger(0)
|
||||
logger.info("Time to make the new snapshot (%s)", ("live" if live else "idle"))
|
||||
try:
|
||||
self.__snapshoting = True
|
||||
await notifier.notify()
|
||||
|
||||
if not live:
|
||||
if self.__wakeup_key:
|
||||
logger.info("Waking up using key %r ...", self.__wakeup_key)
|
||||
self.__hid.send_key_events([
|
||||
(self.__wakeup_key, True),
|
||||
(self.__wakeup_key, False),
|
||||
])
|
||||
if self.__wakeup_move:
|
||||
logger.info("Waking up using mouse move for %d units ...", self.__wakeup_move)
|
||||
self.__hid.send_mouse_move_event(0, 0)
|
||||
self.__hid.send_mouse_move_event(self.__wakeup_move, self.__wakeup_move)
|
||||
|
||||
if self.__online_delay:
|
||||
logger.info("Waiting %.2f seconds for online ...", self.__online_delay)
|
||||
await asyncio.sleep(self.__online_delay)
|
||||
|
||||
retries = self.__retries
|
||||
while retries:
|
||||
snapshot = await self.__streamer.make_snapshot(save=True, load=False, allow_offline=False)
|
||||
if snapshot:
|
||||
logger.info("New snapshot saved: %dx%d", snapshot.width, snapshot.height)
|
||||
break
|
||||
retries -= 1
|
||||
await asyncio.sleep(self.__retries_delay)
|
||||
else:
|
||||
logger.error("Can't make snapshot after %d retries", self.__retries)
|
||||
except Exception: # Этого вообще-то не должно случаться, апи внутри заэксцепчены, но мало ли
|
||||
logger.exception("Unhandled exception while making snapshot")
|
||||
finally:
|
||||
self.__snapshoting = False
|
||||
await notifier.notify()
|
||||
Reference in New Issue
Block a user