合入小程序修改,新增告警功能
This commit is contained in:
129
talkingq-url/services/device_identity_initializer.py
Normal file
129
talkingq-url/services/device_identity_initializer.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from services.database_service_base import DatabaseServiceBase
|
||||
from utils.logger import session_logger
|
||||
|
||||
|
||||
class DeviceIdentityInitializationError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DeviceIdentityInitializationResult:
|
||||
imei: str
|
||||
device_id: str
|
||||
serial_number: str
|
||||
activated: bool
|
||||
|
||||
|
||||
class DeviceIdentityInitializer(DatabaseServiceBase):
|
||||
def __init__(self):
|
||||
super().__init__(service_name="device_identity_initializer")
|
||||
|
||||
async def initialize_by_imei(self, imei: str) -> DeviceIdentityInitializationResult:
|
||||
normalized_imei = str(imei or "").strip()
|
||||
if not normalized_imei:
|
||||
raise DeviceIdentityInitializationError("imei is required")
|
||||
|
||||
db_session = await self.get_session()
|
||||
try:
|
||||
mapping_result = await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT imei, device_id, serial_number, status
|
||||
FROM device_imei_mapping
|
||||
WHERE imei = :imei
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
{"imei": normalized_imei},
|
||||
)
|
||||
mapping = mapping_result.mappings().first()
|
||||
if mapping is None:
|
||||
raise DeviceIdentityInitializationError("imei mapping not found")
|
||||
|
||||
device_id = str(mapping["device_id"]).strip()
|
||||
serial_number = str(mapping["serial_number"]).strip()
|
||||
if not device_id or not serial_number:
|
||||
raise DeviceIdentityInitializationError("imei mapping is incomplete")
|
||||
|
||||
device_auth_result = await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT device_id, serial_number
|
||||
FROM device_auth
|
||||
WHERE device_id = :device_id
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
{"device_id": device_id},
|
||||
)
|
||||
device_auth = device_auth_result.mappings().first()
|
||||
if device_auth is None:
|
||||
await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO device_auth (device_id, serial_number, is_active)
|
||||
VALUES (:device_id, :serial_number, 1)
|
||||
"""
|
||||
),
|
||||
{"device_id": device_id, "serial_number": serial_number},
|
||||
)
|
||||
elif str(device_auth["serial_number"]) != serial_number:
|
||||
raise DeviceIdentityInitializationError("device_auth serial_number conflict")
|
||||
else:
|
||||
await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE device_auth
|
||||
SET is_active = 1
|
||||
WHERE device_id = :device_id
|
||||
"""
|
||||
),
|
||||
{"device_id": device_id},
|
||||
)
|
||||
|
||||
await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE device_imei_mapping
|
||||
SET status = 'activated',
|
||||
activated_at = COALESCE(activated_at, CURRENT_TIMESTAMP)
|
||||
WHERE imei = :imei
|
||||
"""
|
||||
),
|
||||
{"imei": normalized_imei},
|
||||
)
|
||||
await db_session.commit()
|
||||
|
||||
session_logger.info(
|
||||
device_id,
|
||||
"device_identity_initializer",
|
||||
f"IMEI identity initialized: imei={normalized_imei}",
|
||||
)
|
||||
return DeviceIdentityInitializationResult(
|
||||
imei=normalized_imei,
|
||||
device_id=device_id,
|
||||
serial_number=serial_number,
|
||||
activated=str(mapping["status"]) == "activated",
|
||||
)
|
||||
except DeviceIdentityInitializationError:
|
||||
await db_session.rollback()
|
||||
raise
|
||||
except Exception as exc:
|
||||
await db_session.rollback()
|
||||
session_logger.error(
|
||||
normalized_imei,
|
||||
"device_identity_initializer",
|
||||
f"initialize identity failed: {exc}",
|
||||
)
|
||||
raise
|
||||
finally:
|
||||
await db_session.close()
|
||||
|
||||
|
||||
device_identity_initializer = DeviceIdentityInitializer()
|
||||
@@ -1,6 +1,8 @@
|
||||
from typing import Dict, Optional
|
||||
import time
|
||||
from sqlalchemy import select, update, insert, delete
|
||||
from collections.abc import Mapping
|
||||
|
||||
from sqlalchemy import select, update, insert, delete, text
|
||||
from database.models import DeviceFirmwareUpdate
|
||||
from services.database_service_base import DatabaseServiceBase
|
||||
from utils.logger import session_logger
|
||||
@@ -13,7 +15,31 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
self.cache_timestamps = {} # 记录缓存更新时间
|
||||
self.max_cache_size = 1000 # 最大缓存条目数
|
||||
|
||||
async def create_firmware_update(self, device_id: str, firmware_version: str, update_status: str = "success"):
|
||||
async def _get_serial_number(self, db_session, device_id: str) -> str:
|
||||
result = await db_session.execute(
|
||||
text("SELECT serial_number FROM device_auth WHERE device_id = :device_id LIMIT 1"),
|
||||
{"device_id": device_id},
|
||||
)
|
||||
row = result.mappings().first()
|
||||
if row and row.get("serial_number"):
|
||||
return str(row["serial_number"])
|
||||
return ""
|
||||
|
||||
def _row_to_dict(self, row) -> dict:
|
||||
if row is None:
|
||||
return {}
|
||||
if isinstance(row, Mapping):
|
||||
return dict(row)
|
||||
return {
|
||||
"device_id": row.device_id,
|
||||
"firmware_version": row.firmware_version,
|
||||
"update_status": row.update_status,
|
||||
"progress": row.progress,
|
||||
"created_at": row.created_at,
|
||||
"updated_at": row.updated_at,
|
||||
}
|
||||
|
||||
async def create_firmware_update(self, device_id: str, firmware_version: str, update_status: str = "success", progress: float = 0.0):
|
||||
"""新增固件更新记录"""
|
||||
await self._init_database()
|
||||
db_session = await self.get_session()
|
||||
@@ -29,16 +55,18 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
.values(
|
||||
firmware_version=firmware_version,
|
||||
update_status=update_status,
|
||||
progress=0.0
|
||||
progress=progress
|
||||
)
|
||||
)
|
||||
await db_session.execute(update_stmt)
|
||||
else:
|
||||
serial_number = await self._get_serial_number(db_session, device_id)
|
||||
insert_stmt = insert(DeviceFirmwareUpdate).values(
|
||||
device_id=device_id,
|
||||
serial_number=serial_number,
|
||||
firmware_version=firmware_version,
|
||||
update_status=update_status,
|
||||
progress=0.0
|
||||
progress=progress
|
||||
)
|
||||
await db_session.execute(insert_stmt)
|
||||
|
||||
@@ -48,7 +76,7 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
"device_id": device_id,
|
||||
"firmware_version": firmware_version,
|
||||
"update_status": update_status,
|
||||
"progress": 0.0
|
||||
"progress": progress
|
||||
})
|
||||
|
||||
return True
|
||||
@@ -79,7 +107,13 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
finally:
|
||||
await db_session.close()
|
||||
|
||||
async def update_firmware_update(self, device_id: str, firmware_version: str, update_status: str) -> bool:
|
||||
async def update_firmware_update(
|
||||
self,
|
||||
device_id: str,
|
||||
firmware_version: str,
|
||||
update_status: str,
|
||||
progress: Optional[float] = None,
|
||||
) -> bool:
|
||||
"""更新设备固件信息(支持部分字段更新)"""
|
||||
await self._init_database()
|
||||
db_session = await self.get_session()
|
||||
@@ -88,6 +122,8 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
"firmware_version": firmware_version,
|
||||
"update_status": update_status
|
||||
}
|
||||
if progress is not None:
|
||||
update_values["progress"] = progress
|
||||
|
||||
query = select(DeviceFirmwareUpdate).where(DeviceFirmwareUpdate.device_id == device_id)
|
||||
result = await db_session.execute(query)
|
||||
@@ -101,10 +137,13 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
)
|
||||
await db_session.execute(update_stmt)
|
||||
else:
|
||||
serial_number = await self._get_serial_number(db_session, device_id)
|
||||
insert_stmt = insert(DeviceFirmwareUpdate).values(
|
||||
device_id=device_id,
|
||||
serial_number=serial_number,
|
||||
firmware_version=firmware_version,
|
||||
update_status=update_status
|
||||
update_status=update_status,
|
||||
progress=progress if progress is not None else 0.0,
|
||||
)
|
||||
await db_session.execute(insert_stmt)
|
||||
|
||||
@@ -131,8 +170,12 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
await db_session.execute(update_stmt)
|
||||
await db_session.commit()
|
||||
|
||||
if device_id in self.update_cache:
|
||||
self.update_cache[device_id].progress = progress
|
||||
cached_update = self.update_cache.get(device_id)
|
||||
if isinstance(cached_update, dict):
|
||||
cached_update["progress"] = progress
|
||||
elif cached_update is not None:
|
||||
cached_update.progress = progress
|
||||
if cached_update is not None:
|
||||
self.cache_timestamps[device_id] = time.time()
|
||||
|
||||
session_logger.info(device_id, "firmware_update", f"更新进度已更新: {progress:.1f}%")
|
||||
@@ -184,8 +227,10 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
)
|
||||
await db_session.execute(update_stmt)
|
||||
else:
|
||||
serial_number = await self._get_serial_number(db_session, device_id)
|
||||
insert_stmt = insert(DeviceFirmwareUpdate).values(
|
||||
device_id=device_id,
|
||||
serial_number=serial_number,
|
||||
firmware_version=firmware_version,
|
||||
update_status="success" # 默认状态为成功
|
||||
)
|
||||
@@ -264,4 +309,10 @@ class DeviceFirmwareUpdateManager(DatabaseServiceBase):
|
||||
if device_id in self.cache_timestamps:
|
||||
del self.cache_timestamps[device_id]
|
||||
|
||||
device_firmware_update_manager = DeviceFirmwareUpdateManager()
|
||||
async def get_firmware_update_dict(self, device_id: str) -> Optional[dict]:
|
||||
record = await self.get_firmware_update(device_id)
|
||||
if record is None:
|
||||
return None
|
||||
return self._row_to_dict(record)
|
||||
|
||||
device_firmware_update_manager = DeviceFirmwareUpdateManager()
|
||||
|
||||
Reference in New Issue
Block a user