Files
CoRE.Vision/backend/app/services/system.py
T
git_admin a64749ccc8 storage: multi-storage management with per-storage quota
Replace the single fixed /records path with a list of storages and an
active selection (where new recordings go). Quota is now per-storage.

- config: StorageItem(id,name,type,path,quota_gb,nas-meta) + Storage keeps
  global retention_days/segment_seconds; active + items. Migration from the
  old single {path,quota_gb} schema → one local item.
- recorder: write to the active storage; restart_all() repoints on switch;
  NAS-not-mounted guard (never write into the container overlay).
- indexer: scan ALL storage roots so recordings survive an active switch.
- retention: enforce quota PER storage via db.total_size_under /
  oldest_recordings_under (path-prefix LIKE).
- api/storages: GET/POST/PUT/DELETE + activate + policy. NAS uses host-mount
  (backend stores SMB params, generates the mount/fstab command, reports
  ismount status). Retire old POST /api/storage.
- frontend: new "Хранилища" settings tab — table with inline per-row quota,
  add form (local folder / NAS SMB), global policy (segment + retention).
- compose: add shared ./storages:/storages root for extra local folders and
  host-mounted NAS shares.

VERSION 0.0.127.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 19:31:15 +05:00

53 lines
1.7 KiB
Python

"""Системная статистика: диск хранилища, CPU, RAM, аптайм."""
from __future__ import annotations
import os
import shutil
import time
import psutil
from ..config import Config
_START = time.time()
def storage_disk(path: str) -> dict:
"""Использование диска, на котором лежит path (для одного хранилища)."""
try:
usage = shutil.disk_usage(path)
return {
"total_gb": round(usage.total / 1024 ** 3, 1),
"used_gb": round(usage.used / 1024 ** 3, 1),
"free_gb": round(usage.free / 1024 ** 3, 1),
"percent": round(usage.used / usage.total * 100, 1) if usage.total else 0,
}
except OSError:
return {"total_gb": 0, "used_gb": 0, "free_gb": 0, "percent": 0}
def is_mounted(path: str) -> bool:
"""Точка монтирования? (для NAS — признак, что том реально подключён)."""
try:
return os.path.ismount(path)
except OSError:
return False
def system_stats(config: Config) -> dict:
active = config.active_storage()
path = active.path
vm = psutil.virtual_memory()
return {
"uptime_s": int(time.time() - _START),
"cpu_percent": psutil.cpu_percent(interval=None),
"ram_percent": vm.percent,
"ram_used_gb": round(vm.used / 1024 ** 3, 1),
"ram_total_gb": round(vm.total / 1024 ** 3, 1),
"storage_path": path,
"disk": storage_disk(path),
"quota_gb": active.quota_gb,
"retention_days": config.storage.retention_days,
"segment_seconds": config.storage.segment_seconds,
}