update server
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
"""Load, download, and validate the volume-measurement configuration."""
|
||||
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
REQUIRED_FIELDS = {
|
||||
"q_in_val", "dt", "p_max", "fit_low", "fit_high",
|
||||
"T_delta", "xa_full", "num_runs",
|
||||
}
|
||||
|
||||
|
||||
def default_config_path() -> Path:
|
||||
"""Return the config path without exposing a file picker in the GUI."""
|
||||
override = os.environ.get("REINLOOP_VOLUME_CONFIG")
|
||||
if override:
|
||||
return Path(override).expanduser().resolve()
|
||||
base_dir = (Path(sys.executable).resolve().parent
|
||||
if getattr(sys, "frozen", False)
|
||||
else Path(__file__).resolve().parent.parent)
|
||||
return base_dir / "config" / "volume_measurement.json"
|
||||
|
||||
|
||||
def load_volume_config(path=None) -> dict:
|
||||
"""Read exactly eight validated parameters from a JSON object."""
|
||||
config_path = Path(path).resolve() if path else default_config_path()
|
||||
try:
|
||||
with config_path.open("r", encoding="utf-8") as file_obj:
|
||||
config = json.load(file_obj)
|
||||
except FileNotFoundError as exc:
|
||||
raise ValueError(f"容积测试配置文件不存在: {config_path}") from exc
|
||||
except json.JSONDecodeError as exc:
|
||||
raise ValueError(f"容积测试配置不是有效 JSON: {exc}") from exc
|
||||
except OSError as exc:
|
||||
raise ValueError(f"无法读取容积测试配置: {exc}") from exc
|
||||
|
||||
return validate_volume_config(config)
|
||||
|
||||
|
||||
def validate_volume_config(config) -> dict:
|
||||
"""Validate exactly eight parameters and normalize numeric values."""
|
||||
|
||||
if not isinstance(config, dict):
|
||||
raise ValueError("容积测试配置必须是 JSON 对象")
|
||||
actual_fields = set(config)
|
||||
if actual_fields != REQUIRED_FIELDS:
|
||||
missing = sorted(REQUIRED_FIELDS - actual_fields)
|
||||
extra = sorted(actual_fields - REQUIRED_FIELDS)
|
||||
raise ValueError(f"配置字段错误,缺少={missing},多余={extra}")
|
||||
|
||||
for field in REQUIRED_FIELDS - {"num_runs"}:
|
||||
value = config[field]
|
||||
if (isinstance(value, bool) or not isinstance(value, (int, float))
|
||||
or not math.isfinite(float(value))):
|
||||
raise ValueError(f"参数 {field} 必须是有限数字")
|
||||
|
||||
runs = config["num_runs"]
|
||||
if isinstance(runs, bool) or not isinstance(runs, int) or runs <= 0:
|
||||
raise ValueError("参数 num_runs 必须是正整数")
|
||||
if config["q_in_val"] <= 0:
|
||||
raise ValueError("q_in_val 必须大于 0")
|
||||
if config["dt"] <= 0 or config["p_max"] <= 0:
|
||||
raise ValueError("dt 和 p_max 必须大于 0")
|
||||
if config["fit_low"] < 0 or config["fit_high"] <= config["fit_low"]:
|
||||
raise ValueError("必须满足 0 <= fit_low < fit_high")
|
||||
if config["fit_high"] > config["p_max"]:
|
||||
raise ValueError("fit_high 不能大于 p_max")
|
||||
if config["xa_full"] <= 0:
|
||||
raise ValueError("xa_full 必须大于 0")
|
||||
|
||||
return {
|
||||
"q_in_val": float(config["q_in_val"]),
|
||||
"dt": float(config["dt"]),
|
||||
"p_max": float(config["p_max"]),
|
||||
"fit_low": float(config["fit_low"]),
|
||||
"fit_high": float(config["fit_high"]),
|
||||
"T_delta": float(config["T_delta"]),
|
||||
"xa_full": float(config["xa_full"]),
|
||||
"num_runs": runs,
|
||||
}
|
||||
|
||||
|
||||
def _post_volume_request(payload, timeout=10):
|
||||
import requests
|
||||
from api import data_record_url
|
||||
|
||||
try:
|
||||
response = requests.post(data_record_url, json=payload, timeout=timeout)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
except Exception as exc:
|
||||
raise ValueError(f"连接云端容积参数服务失败: {exc}") from exc
|
||||
|
||||
if not result.get("success"):
|
||||
raise ValueError(result.get("errMsg", "云端拒绝容积参数请求"))
|
||||
return result
|
||||
|
||||
|
||||
def create_volume_config_request(timeout=10) -> dict:
|
||||
"""Create exactly one cloud request after the customer clicks Test."""
|
||||
from api import the_folder
|
||||
|
||||
result = _post_volume_request({
|
||||
"type": "createVolumeConfigRequest",
|
||||
"deviceId": the_folder,
|
||||
}, timeout=timeout)
|
||||
if not result.get("requestId") or not result.get("expiresAtMs"):
|
||||
raise ValueError("云端未返回有效的容积参数请求编号")
|
||||
return {
|
||||
"request_id": result["requestId"],
|
||||
"expires_at_ms": int(result["expiresAtMs"]),
|
||||
}
|
||||
|
||||
|
||||
def poll_volume_config_request(request_id: str, timeout=10) -> dict:
|
||||
"""Poll one request; download and validate JSON only when it is ready."""
|
||||
import requests
|
||||
from api import the_folder
|
||||
|
||||
result = _post_volume_request({
|
||||
"type": "getVolumeConfigRequest",
|
||||
"deviceId": the_folder,
|
||||
"requestId": request_id,
|
||||
}, timeout=timeout)
|
||||
if result.get("expired"):
|
||||
return {"ready": False, "expired": True}
|
||||
if not result.get("ready"):
|
||||
return {"ready": False, "expired": False}
|
||||
|
||||
try:
|
||||
response = requests.get(result["url"], timeout=timeout)
|
||||
response.raise_for_status()
|
||||
config = response.json()
|
||||
except Exception as exc:
|
||||
raise ValueError(f"下载或解析容积参数 JSON 失败: {exc}") from exc
|
||||
return {
|
||||
"ready": True,
|
||||
"expired": False,
|
||||
"config": validate_volume_config(config),
|
||||
}
|
||||
|
||||
|
||||
def acknowledge_volume_config_request(request_id: str, timeout=10) -> None:
|
||||
"""Delete the consumed/abandoned request and its temporary JSON file."""
|
||||
from api import the_folder
|
||||
|
||||
_post_volume_request({
|
||||
"type": "ackVolumeConfigRequest",
|
||||
"deviceId": the_folder,
|
||||
"requestId": request_id,
|
||||
}, timeout=timeout)
|
||||
Reference in New Issue
Block a user