feat: add device registration observation

This commit is contained in:
QiuSW
2026-07-21 09:27:05 +08:00
parent 20bdf4a8ce
commit 69f4517958
21 changed files with 958 additions and 5 deletions
+83
View File
@@ -27,6 +27,7 @@ from apps.api.image_tasks import (
from apps.api.models import ImageGenerationTask
from apps.api.serializers import (
AnalyzeImagesRequestSerializer,
DeviceRegistrationRequestSerializer,
GenerateImageRequestSerializer,
GenerateTitleRequestSerializer,
RechargeCreateRequestSerializer,
@@ -63,6 +64,12 @@ from apps.billing.services import (
query_and_apply_recharge_payment,
)
from apps.portal.models import DownloadRelease
from apps.licensing.authentication import DeviceSessionAuthentication
from apps.licensing.services import (
DeviceRegistrationError,
record_device_heartbeat,
register_device,
)
logger = logging.getLogger(__name__)
@@ -263,6 +270,82 @@ class ModelsView(ExternalApiView):
)
def _device_response(device) -> dict:
return {
"product_code": device.product_code,
"platform": device.platform,
"client_version": device.client_version,
"status": device.status,
"first_seen_at": device.first_seen_at.isoformat(),
"last_seen_at": device.last_seen_at.isoformat(),
}
class DeviceRegistrationView(ExternalApiView):
def post(self, request):
serializer = DeviceRegistrationRequestSerializer(data=request.data)
if not serializer.is_valid():
return Response(
api_error("bad_request", "参数错误"),
status=status.HTTP_400_BAD_REQUEST,
)
data = serializer.validated_data
try:
result = register_device(
user=request.user,
api_key=request.auth,
product_code=data["product_code"],
device_id_version=data["device_id_version"],
device_id=data["device_id"],
public_key=data["installation_public_key"],
platform=data["platform"],
client_version=data["client_version"],
)
except DeviceRegistrationError as exc:
return Response(
api_error(exc.code, exc.message),
status=status.HTTP_403_FORBIDDEN,
)
return Response(
{
"device": _device_response(result.device),
"device_session_token": result.session_token,
"expires_at": result.session.expires_at.isoformat(),
},
status=status.HTTP_201_CREATED if result.created else status.HTTP_200_OK,
)
class DeviceSessionApiView(APIView):
authentication_classes = (DeviceSessionAuthentication,)
permission_classes = (IsAuthenticated,)
def permission_denied(self, request, message=None, code=None):
if request.authenticators and not request.successful_authenticator:
raise DeviceSessionAuthentication.authentication_failed(request)
super().permission_denied(request, message=message, code=code)
class DeviceHeartbeatView(DeviceSessionApiView):
def post(self, request):
try:
updated = record_device_heartbeat(request.auth)
except DeviceRegistrationError as exc:
return Response(
api_error(exc.code, exc.message),
status=status.HTTP_403_FORBIDDEN,
)
request.auth.device.refresh_from_db()
return Response(
{
"device": _device_response(request.auth.device),
"activity_updated": updated,
"expires_at": request.auth.expires_at.isoformat(),
},
status=status.HTTP_200_OK,
)
def _release_unpublished_response(platform: str) -> dict:
return {
"platform": platform,