Add OTA package upload functionality and UI enhancements
- Introduced a new endpoint for uploading OTA packages in backend/routes/ota.py. - Implemented file handling and MD5 checksum calculation for OTA packages. - Updated frontend API to support OTA package uploads with a new uploadOtaPackage function. - Enhanced the OTA management UI to include file upload options and improved layout. - Updated requirements.txt to include boto3 for S3 interactions. - Made various UI adjustments for better user experience and consistency.
This commit is contained in:
+72
-1
@@ -1,11 +1,22 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Body
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Body, UploadFile, File, Form
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
from dotenv import load_dotenv
|
||||
from database import get_db
|
||||
from models.ota import Ota
|
||||
from schemas import OtaCreate, OtaUpdate, OtaResponse
|
||||
from response import ApiResponse, PageData
|
||||
from ota_storage import (
|
||||
OTA_MODEL_X8,
|
||||
OTA_MODEL_X9,
|
||||
OTA_UPLOAD_MODELS,
|
||||
read_upload_content_and_md5,
|
||||
save_x9_package_local,
|
||||
upload_x8_package_to_s3,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Configure logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -13,6 +24,66 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api/ota", tags=["ota"])
|
||||
|
||||
|
||||
@router.post("/upload-package", response_model=ApiResponse)
|
||||
async def upload_ota_package(
|
||||
model: str = Form(..., description="设备型号"),
|
||||
package_file: UploadFile = File(..., description="OTA 升级包"),
|
||||
):
|
||||
"""上传 OTA 升级包:计算 MD5;X8 上传 S3 为 LUXSIN_X8.PKG,X9 本地保存为 LUXSIN.PKG"""
|
||||
try:
|
||||
model = (model or "").strip()
|
||||
if model not in OTA_UPLOAD_MODELS:
|
||||
return ApiResponse(
|
||||
code=0,
|
||||
msg=f"当前仅支持为 {OTA_MODEL_X8}、{OTA_MODEL_X9} 上传升级包",
|
||||
data=None,
|
||||
)
|
||||
if not package_file or not package_file.filename:
|
||||
return ApiResponse(code=0, msg="请选择升级包文件", data=None)
|
||||
|
||||
logger.info(
|
||||
"Uploading OTA package: model=%s, filename=%s",
|
||||
model,
|
||||
package_file.filename,
|
||||
)
|
||||
|
||||
content, md5_hex = await read_upload_content_and_md5(package_file)
|
||||
|
||||
if model == OTA_MODEL_X9:
|
||||
saved_name, download_url = save_x9_package_local(content, md5_hex)
|
||||
return ApiResponse(
|
||||
code=1,
|
||||
msg="success",
|
||||
data={
|
||||
"md5": md5_hex,
|
||||
"filename": saved_name,
|
||||
"url": download_url,
|
||||
},
|
||||
)
|
||||
|
||||
if model == OTA_MODEL_X8:
|
||||
saved_name, download_url, s3_key = upload_x8_package_to_s3(
|
||||
content, md5_hex
|
||||
)
|
||||
return ApiResponse(
|
||||
code=1,
|
||||
msg="success",
|
||||
data={
|
||||
"md5": md5_hex,
|
||||
"filename": saved_name,
|
||||
"url": download_url,
|
||||
"s3_key": s3_key,
|
||||
},
|
||||
)
|
||||
|
||||
return ApiResponse(code=0, msg="不支持的设备型号", data=None)
|
||||
except ValueError as e:
|
||||
return ApiResponse(code=0, msg=str(e), data=None)
|
||||
except Exception as e:
|
||||
logger.error("Error uploading OTA package: %s", e, exc_info=True)
|
||||
return ApiResponse(code=0, msg=f"上传失败:{e}", data=None)
|
||||
|
||||
|
||||
@router.get("/", response_model=ApiResponse)
|
||||
def get_ota_list(
|
||||
skip: int = Query(0, ge=0, description="跳过记录数"),
|
||||
|
||||
Reference in New Issue
Block a user