106 lines
4.6 KiB
Python
Executable File
106 lines
4.6 KiB
Python
Executable File
# /opt/docker/dev/service_finder/backend/app/services/maintenance_service.py
|
|
import os
|
|
import logging
|
|
import shutil
|
|
from datetime import datetime, timedelta, timezone
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, and_
|
|
from app.models.asset import Asset, AssetTelemetry
|
|
from app.services.config_service import config # 2.0 Dinamikus konfig
|
|
from app.services.notification_service import NotificationService
|
|
|
|
logger = logging.getLogger("Maintenance-Service-2.0")
|
|
|
|
class MaintenanceService:
|
|
"""
|
|
Sentinel Master Maintenance Service 2.0.
|
|
Felelős a rendszer tisztításáért és a prediktív karbantartási riasztásokért.
|
|
"""
|
|
|
|
@staticmethod
|
|
async def cleanup_old_files(db: AsyncSession):
|
|
"""
|
|
Admin-vezérelt NAS takarítás.
|
|
A megőrzési időt (napokban) az adatbázisból veszi.
|
|
"""
|
|
try:
|
|
storage_path = await config.get_setting(db, "storage_nas_path", default="/mnt/nas/app_data")
|
|
retention_days = await config.get_setting(db, "storage_retention_days", default=365)
|
|
|
|
limit = datetime.now() - timedelta(days=int(retention_days))
|
|
deleted_count = 0
|
|
|
|
if not os.path.exists(storage_path):
|
|
logger.warning(f"A tárolási útvonal nem található: {storage_path}")
|
|
return 0
|
|
|
|
for root, dirs, files in os.walk(storage_path):
|
|
for file in files:
|
|
file_path = os.path.join(root, file)
|
|
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
|
|
|
|
if file_time < limit:
|
|
os.remove(file_path)
|
|
deleted_count += 1
|
|
|
|
logger.info(f"🗑️ NAS takarítás kész. Törölve: {deleted_count} lejárt fájl.")
|
|
return deleted_count
|
|
except Exception as e:
|
|
logger.error(f"Hiba a takarítás során: {e}")
|
|
return 0
|
|
|
|
@staticmethod
|
|
async def check_maintenance_intervals(db: AsyncSession):
|
|
"""
|
|
Prediktív karbantartás: Összeveti a Robot 3 gyári adatait a valós futásteljesítménnyel.
|
|
Ha egy autó közeledik az olajcseréhez (pl. 1000 km-en belül), riasztást generál.
|
|
"""
|
|
try:
|
|
# Admin beállítás: hány km-rel a szerviz előtt szóljunk?
|
|
km_threshold = await config.get_setting(db, "maint_km_alert_threshold", default=1000)
|
|
|
|
# Lekérjük az összes autót a telemetriával együtt
|
|
stmt = select(Asset, AssetTelemetry).join(AssetTelemetry).where(Asset.status == "active")
|
|
result = await db.execute(stmt)
|
|
|
|
alerts_generated = 0
|
|
for asset, telemetry in result.all():
|
|
# A Robot 3 által feltöltött gyári adat (pl. 15.000 km)
|
|
interval = asset.factory_data.get("oil_change_km") if asset.factory_data else None
|
|
last_service_km = asset.factory_data.get("last_service_km", 0)
|
|
|
|
if interval and telemetry.current_mileage:
|
|
next_service_due = last_service_km + interval
|
|
remaining_km = next_service_due - telemetry.current_mileage
|
|
|
|
if 0 <= remaining_km <= int(km_threshold):
|
|
# Értesítés küldése a Notification Centerbe és Emailben
|
|
await NotificationService.send_direct_notification(
|
|
db,
|
|
user_id=asset.owner_id,
|
|
message_key="maintenance_due",
|
|
variables={
|
|
"vehicle": f"{asset.license_plate}",
|
|
"type": "Olajcsere",
|
|
"remaining": remaining_km
|
|
}
|
|
)
|
|
alerts_generated += 1
|
|
|
|
return alerts_generated
|
|
except Exception as e:
|
|
logger.error(f"Karbantartás ellenőrzési hiba: {e}")
|
|
return 0
|
|
|
|
@staticmethod
|
|
async def delete_validated_evidence(db: AsyncSession, document_id: str):
|
|
"""
|
|
Validáció utáni képkezelés.
|
|
Az adminban állítható, hogy töröljük-e a bizonyítékot a hitelesítés után.
|
|
"""
|
|
should_delete = await config.get_setting(db, "storage_delete_after_validation", default=False)
|
|
|
|
if should_delete:
|
|
# Itt a Document modell alapján megkeressük a fájlt és töröljük
|
|
# (A biztonság kedvéért naplózzuk a Sentinelbe)
|
|
pass |