Files
banban/talkingq-url/services/device_identity_initializer.py
2026-05-09 09:46:06 +08:00

130 lines
4.3 KiB
Python

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()