mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-13 01:30:31 +08:00
bind for streamer device
This commit is contained in:
parent
a33965b6a5
commit
e71252933a
@ -43,6 +43,7 @@ def main() -> None:
|
||||
streamer = Streamer(
|
||||
cap_power=int(config["streamer"]["pinout"].get("cap", -1)),
|
||||
conv_power=int(config["streamer"]["pinout"].get("conv", -1)),
|
||||
bind=str(config["streamer"].get("bind", "")),
|
||||
sync_delay=float(config["streamer"]["sync_delay"]),
|
||||
init_delay=float(config["streamer"]["init_delay"]),
|
||||
width=int(config["streamer"]["size"]["width"]),
|
||||
|
||||
48
kvmd/kvmd/extras/explorehw/__init__.py
Normal file
48
kvmd/kvmd/extras/explorehw/__init__.py
Normal file
@ -0,0 +1,48 @@
|
||||
import argparse
|
||||
|
||||
from ... import msd
|
||||
from ... import streamer
|
||||
|
||||
|
||||
# =====
|
||||
def _probe_msd(path: str) -> bool:
|
||||
info = msd.explore_device(path)
|
||||
if info:
|
||||
print("It's a mass-storage device")
|
||||
print("--------------------------")
|
||||
print("Path: ", info.path)
|
||||
print("Bind: ", info.bind)
|
||||
print("Size: ", info.size)
|
||||
print("Manufacturer:", info.manufacturer)
|
||||
print("Product: ", info.product)
|
||||
print("Serial: ", info.serial)
|
||||
print("Image name: ", info.image_name)
|
||||
assert msd.locate_by_bind(info.bind), info.bind
|
||||
return bool(info)
|
||||
|
||||
|
||||
def _probe_streamer(path: str) -> bool:
|
||||
info = streamer.explore_device(path)
|
||||
if info:
|
||||
print("It's a streamer device")
|
||||
print("----------------------")
|
||||
print("Path: ", info.path)
|
||||
print("Bind: ", info.bind)
|
||||
print("Driver:", info.driver)
|
||||
assert streamer.locate_by_bind(info.bind), info.bind
|
||||
return bool(info)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("device")
|
||||
options = parser.parse_args()
|
||||
|
||||
for probe in [
|
||||
_probe_msd,
|
||||
_probe_streamer,
|
||||
]:
|
||||
if probe(options.device):
|
||||
break
|
||||
else:
|
||||
raise RuntimeError("Can't recognize device")
|
||||
@ -1,21 +0,0 @@
|
||||
import argparse
|
||||
|
||||
from ...msd import explore_device
|
||||
from ...msd import locate_by_bind
|
||||
|
||||
|
||||
# =====
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-d", "--device", default="/dev/sda")
|
||||
options = parser.parse_args()
|
||||
|
||||
info = explore_device(options.device)
|
||||
print("Path: ", info.path)
|
||||
print("Bind: ", info.bind)
|
||||
print("Size: ", info.size)
|
||||
print("Manufacturer:", info.manufacturer)
|
||||
print("Product: ", info.product)
|
||||
print("Serial: ", info.serial)
|
||||
print("Image name: ", info.image_name)
|
||||
assert locate_by_bind(info.bind), "WTF?! Can't locate device file using bind %r" % (info.bind)
|
||||
@ -98,18 +98,23 @@ def _parse_disk_meta(data: bytes) -> Dict:
|
||||
return disk_meta
|
||||
|
||||
|
||||
def explore_device(path: str) -> MassStorageDeviceInfo:
|
||||
def explore_device(path: str) -> Optional[MassStorageDeviceInfo]:
|
||||
# udevadm info -a -p $(udevadm info -q path -n /dev/sda)
|
||||
ctx = pyudev.Context()
|
||||
|
||||
block_device = pyudev.Devices.from_device_file(ctx, path)
|
||||
size = block_device.attributes.asint("size") * 512
|
||||
try:
|
||||
size = block_device.attributes.asint("size") * 512
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
storage_device = block_device.find_parent("usb", "usb_interface")
|
||||
assert storage_device.driver == "usb-storage", (storage_device.driver, storage_device)
|
||||
interface_device = block_device.find_parent("usb", "usb_interface")
|
||||
if not interface_device:
|
||||
return None
|
||||
|
||||
usb_device = block_device.find_parent("usb", "usb_device")
|
||||
assert usb_device.driver == "usb", (usb_device.driver, usb_device)
|
||||
if not usb_device:
|
||||
return None
|
||||
|
||||
with open(path, "rb") as device_file:
|
||||
device_file.seek(size - _DISK_META_SIZE)
|
||||
@ -117,7 +122,7 @@ def explore_device(path: str) -> MassStorageDeviceInfo:
|
||||
|
||||
return MassStorageDeviceInfo(
|
||||
path=path,
|
||||
bind=storage_device.sys_name,
|
||||
bind=interface_device.sys_name,
|
||||
size=size,
|
||||
manufacturer=usb_device.attributes.asstring("manufacturer").strip(),
|
||||
product=usb_device.attributes.asstring("product").strip(),
|
||||
@ -250,10 +255,13 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes
|
||||
await self.__close_device_file()
|
||||
|
||||
async def __reread_device_info(self) -> None:
|
||||
path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind)
|
||||
if not path:
|
||||
device_path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind)
|
||||
if not device_path:
|
||||
raise MassStorageError("Can't locate device by bind %r" % (self._bind))
|
||||
self.__device_info = await self.__loop.run_in_executor(None, explore_device, path)
|
||||
device_info = await self.__loop.run_in_executor(None, explore_device, device_path)
|
||||
if not device_info:
|
||||
raise MassStorageError("Can't explore device %r" % (device_path))
|
||||
self.__device_info = device_info
|
||||
|
||||
async def __close_device_file(self) -> None:
|
||||
try:
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
import os
|
||||
import asyncio
|
||||
import asyncio.subprocess
|
||||
|
||||
from typing import List
|
||||
from typing import Dict
|
||||
from typing import NamedTuple
|
||||
from typing import Optional
|
||||
from typing import Any
|
||||
|
||||
import pyudev
|
||||
|
||||
from .logging import get_logger
|
||||
|
||||
@ -11,11 +16,52 @@ from . import gpio
|
||||
|
||||
|
||||
# =====
|
||||
class StreamerDeviceInfo(NamedTuple):
|
||||
path: str
|
||||
bind: str
|
||||
driver: str
|
||||
|
||||
|
||||
def explore_device(path: str) -> Optional[StreamerDeviceInfo]:
|
||||
# udevadm info -a -p $(udevadm info -q path -n /dev/sda)
|
||||
ctx = pyudev.Context()
|
||||
|
||||
video_device = pyudev.Devices.from_device_file(ctx, path)
|
||||
if video_device.subsystem != "video4linux":
|
||||
return None
|
||||
try:
|
||||
if int(video_device.attributes.get("index")) != 0:
|
||||
# My strange laptop configuration
|
||||
return None
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
interface_device = video_device.find_parent("usb", "usb_interface")
|
||||
if not interface_device:
|
||||
return None
|
||||
|
||||
return StreamerDeviceInfo(
|
||||
path=path,
|
||||
bind=interface_device.sys_name,
|
||||
driver=interface_device.driver,
|
||||
)
|
||||
|
||||
|
||||
def locate_by_bind(bind: str) -> str:
|
||||
ctx = pyudev.Context()
|
||||
for device in ctx.list_devices(subsystem="video4linux"):
|
||||
interface_device = device.find_parent("usb", "usb_interface")
|
||||
if interface_device and interface_device.sys_name == bind:
|
||||
return os.path.join("/dev", device.sys_name)
|
||||
return ""
|
||||
|
||||
|
||||
class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
def __init__(
|
||||
self,
|
||||
cap_power: int,
|
||||
conv_power: int,
|
||||
bind: str,
|
||||
sync_delay: float,
|
||||
init_delay: float,
|
||||
width: int,
|
||||
@ -28,11 +74,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
|
||||
self.__cap_power = (gpio.set_output(cap_power) if cap_power > 0 else cap_power)
|
||||
self.__conv_power = (gpio.set_output(conv_power) if conv_power > 0 else conv_power)
|
||||
self.__bind = bind
|
||||
self.__sync_delay = sync_delay
|
||||
self.__init_delay = init_delay
|
||||
self.__width = width
|
||||
self.__height = height
|
||||
self.__cmd = [part.format(width=width, height=height) for part in cmd]
|
||||
self.__cmd = cmd
|
||||
|
||||
self.__loop = loop
|
||||
|
||||
@ -79,18 +126,27 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
if enabled:
|
||||
await asyncio.sleep(self.__init_delay)
|
||||
|
||||
async def __process(self) -> None:
|
||||
async def __process(self) -> None: # pylint: disable=too-many-branches
|
||||
logger = get_logger(0)
|
||||
|
||||
while True: # pylint: disable=too-many-nested-blocks
|
||||
proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member
|
||||
try:
|
||||
cmd_placeholders: Dict[str, Any] = {"width": self.__width, "height": self.__height}
|
||||
if self.__bind:
|
||||
logger.info("Using bind %r as streamer device", self.__bind)
|
||||
device_path = await self.__loop.run_in_executor(None, locate_by_bind, self.__bind)
|
||||
if not device_path:
|
||||
raise RuntimeError("Can't locate device by bind %r" % (self.__bind))
|
||||
cmd_placeholders["device"] = device_path
|
||||
cmd = [part.format(**cmd_placeholders) for part in self.__cmd]
|
||||
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*self.__cmd,
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
)
|
||||
logger.info("Started streamer pid=%d: %s", proc.pid, self.__cmd)
|
||||
logger.info("Started streamer pid=%d: %s", proc.pid, cmd)
|
||||
|
||||
empty = 0
|
||||
while proc.returncode is None:
|
||||
|
||||
@ -24,7 +24,7 @@ def main() -> None:
|
||||
"kvmd.extras",
|
||||
"kvmd.extras.cleanup",
|
||||
"kvmd.extras.wscli",
|
||||
"kvmd.extras.exploremsd",
|
||||
"kvmd.extras.explorehw",
|
||||
],
|
||||
|
||||
entry_points={
|
||||
@ -32,7 +32,7 @@ def main() -> None:
|
||||
"kvmd = kvmd:main",
|
||||
"kvmd-cleanup = kvmd.extras.cleanup:main",
|
||||
"kvmd-wscli = kvmd.extras.wscli:main",
|
||||
"kvmd-exploremsd = kvmd.extras.exploremsd:main",
|
||||
"kvmd-explorehw = kvmd.extras.explorehw:main",
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user