upload img to qiniu

This commit is contained in:
gcw_4spBpAfv
2026-04-20 19:03:20 +08:00
parent e030f3a194
commit ba5ca7e0b3
3 changed files with 201 additions and 4 deletions

View File

@@ -1406,6 +1406,112 @@ class NetworkManager:
self.logger.error(f"[LOG_UPLOAD] 上传异常: {e}")
self.safe_enqueue({"result": "log_upload_failed", "reason": str(e)[:100]}, 2)
def _upload_image_file(self, image_path, upload_url, upload_token, key, shoot_id, outlink):
"""上传图片文件到指定URL自动检测网络类型WiFi使用requests4G使用AT HTTP命令
Args:
image_path: 本地图片文件路径
upload_url: 上传目标URL例如 "https://upload.qiniup.com"
upload_token: 上传token
key: 文件key例如 "shootPic/123456.bmp"
shoot_id: 射击ID
outlink: 外链域名可选用于构建访问URL
"""
# 自动检测网络类型,选择上传路径
if self._network_type == "wifi" and self.is_wifi_connected():
mode = "wifi"
else:
mode = "4g"
self.logger.info(f"[IMAGE_UPLOAD] Using {mode} path, image: {image_path}")
try:
if mode == "wifi":
# ---- WiFi path: 使用 requests 库上传 ----
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
with open(image_path, 'rb') as f:
files = {'file': (os.path.basename(image_path), f, 'application/octet-stream')}
data = {'token': upload_token, 'key': key}
# 测试将HTTPS转为HTTP
wifi_upload_url = upload_url.replace('https://', 'http://', 1)
self.logger.info(f"[IMAGE_UPLOAD] WiFi upload URL: {wifi_upload_url}")
response = requests.post(wifi_upload_url, files=files, data=data, timeout=120, verify=False)
response.raise_for_status()
result_json = response.json()
uploaded_key = result_json.get('key', key)
self.logger.info(f"[IMAGE_UPLOAD] WiFi upload ok: key={uploaded_key}")
access_url = None
if outlink:
access_url = f"https://{outlink}/{uploaded_key}"
response_data = {
"result": "image_upload_ok",
"shootId": shoot_id,
"key": uploaded_key,
"via": "wifi",
}
if access_url:
response_data["url"] = access_url
self.safe_enqueue(response_data, 2)
else:
# ---- 4G path: 使用 FourGUploadManager AT命令上传 ----
import importlib.util
spec = importlib.util.spec_from_file_location(
"four_g_upload_manager",
os.path.join(os.path.dirname(__file__), "4g_upload_manager.py")
)
upload_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(upload_module)
FourGUploadManager = upload_module.FourGUploadManager
# 实例化4G上传管理器
uploader = FourGUploadManager(hardware_manager.at_client)
# 执行上传
result = uploader.upload_image(image_path, upload_url, upload_token, key)
if result.get("success"):
uploaded_key = result.get("key", key)
self.logger.info(f"[IMAGE_UPLOAD] 4G upload ok: key={uploaded_key}")
access_url = None
if outlink:
access_url = f"https://{outlink}/{uploaded_key}"
response_data = {
"result": "image_upload_ok",
"shootId": shoot_id,
"key": uploaded_key,
"via": "4g",
}
if access_url:
response_data["url"] = access_url
self.safe_enqueue(response_data, 2)
else:
error_msg = result.get("error", "unknown_error")
self.logger.error(f"[IMAGE_UPLOAD] 4G upload failed: {error_msg}")
self.safe_enqueue({
"result": "image_upload_failed",
"shootId": shoot_id,
"reason": error_msg[:100]
}, 2)
except Exception as e:
self.logger.error(f"[IMAGE_UPLOAD] upload exception ({mode}): {e}")
self.safe_enqueue({
"result": "image_upload_failed",
"shootId": shoot_id,
"reason": str(e)[:100]
}, 2)
def generate_token(self, device_id):
"""生成用于 HTTP 接口鉴权的 TokenHMAC-SHA256"""
SALT = "shootMessageFire"
@@ -1592,6 +1698,64 @@ class NetworkManager:
self.safe_enqueue({'data':{'l': len(self._raw_line_data), 'v': v}, 'cmd': 41})
self.logger.info(f"已下载{len(self._raw_line_data)} 全部:{t} 版本:{v}")
elif logged_in and msg_type == 100:
self.logger.info(f"[IMAGE_UPLOAD] 收到图片上传命令 {body}")
if isinstance(body, dict):
upload_url = body.get("uploadUrl")
upload_token = body.get("token")
shoot_id = body.get("shootId")
outlink = body.get("outlink", "")
hardware_manager.start_idle_timer() # 重新计时
# 验证必需字段
if not upload_url or not upload_token or not shoot_id:
self.logger.error("[IMAGE_UPLOAD] 缺少必需参数: uploadUrl, token 或 shootId")
self.safe_enqueue({"result": "image_upload_failed", "reason": "missing_params"}, 2)
else:
self.logger.info(f"[IMAGE_UPLOAD] 收到图片上传命令shootId: {shoot_id}")
# 查找文件名中包含 shoot_id 的图片文件文件名格式shot_{shoot_id}_*.bmp
image_extensions = ('.bmp', '.jpg', '.jpeg', '.png')
photo_dir = config.PHOTO_DIR
target_image = None
try:
if os.path.isdir(photo_dir):
# 优先查找文件名中包含 shoot_id 的图片
matched_images = [
f for f in os.listdir(photo_dir)
if f.lower().endswith(image_extensions) and shoot_id in f
]
if matched_images:
# 按修改时间排序,取最新的匹配文件
matched_images.sort(
key=lambda f: os.path.getmtime(os.path.join(photo_dir, f)),
reverse=True
)
target_image = os.path.join(photo_dir, matched_images[0])
self.logger.info(f"[IMAGE_UPLOAD] 找到匹配shootId的图片: {matched_images[0]}")
else:
self.logger.warning(f"[IMAGE_UPLOAD] 未找到包含shootId={shoot_id}的图片文件")
except Exception as e:
self.logger.error(f"[IMAGE_UPLOAD] 查找图片失败: {e}")
if not target_image:
self.logger.error(f"[IMAGE_UPLOAD] 未找到shootId={shoot_id}对应的图片文件")
self.safe_enqueue({"result": "image_upload_failed", "reason": "no_image_found", "shootId": shoot_id}, 2)
else:
# 构建上传key
ext = os.path.splitext(target_image)[1].lower()
key = f"shootPic/{self.device_id}/{shoot_id}{ext}"
self.logger.info(f"[IMAGE_UPLOAD] 准备上传: {target_image} -> {key}")
# 在新线程中执行上传,避免阻塞主循环
import _thread
_thread.start_new_thread(
self._upload_image_file,
(target_image, upload_url, upload_token, key, shoot_id, outlink)
)
# 立即返回已入队确认
self.safe_enqueue({"result": "image_upload_queued", "shootId": shoot_id}, 2)
# 处理业务指令
elif logged_in and isinstance(body, dict):
inner_cmd = None
@@ -1753,6 +1917,7 @@ class NetworkManager:
self._upload_log_file,
(upload_url, wifi_ssid, wifi_password, include_rotated, max_files, archive_format)
)
else: # data的结构不是 dict
self.logger.info(f"[NET] body={body}, {time.time()}")
else: