3 次程式碼提交

作者 SHA1 備註 提交日期
  Lorenzo Pollutri ecd8c86dff bug fix 2 5 天之前
  Lorenzo Pollutri 6ca4ff7cb8 core sync bugfix 5 天之前
  Lorenzo Pollutri 468980024b sync_core test 6 天之前
共有 2 個檔案被更改,包括 136 行新增9 行删除
分割檢視
  1. +26
    -5
      app.py
  2. +110
    -4
      routes/reslevis.py

+ 26
- 5
app.py 查看文件

@@ -132,15 +132,36 @@ app.add_middleware(
allow_headers=["*"],
)

# app.py
EXACT_PROXY_PATHS = {
"/reslevis/postGateway",
"/reslevis/updateGateway",
"/reslevis/postTracker",
"/reslevis/updateTracker",
"/reslevis/postTrack",
"/reslevis/updateTrack",
"/reslevis/postZone",
"/reslevis/updateZone",
}

PREFIX_PROXY_PATHS = {
"/reslevis/removeGateway/",
"/reslevis/removeTracker/",
"/reslevis/removeTrack/",
"/reslevis/removeZone/",
}

def _should_proxy(path: str) -> bool:
return path in EXACT_PROXY_PATHS or any(path.startswith(p) for p in PREFIX_PROXY_PATHS)

#ResLevis CORE middleware
@app.middleware("http")
async def local_then_core(request: Request, call_next):
# only proxy CRUD for Reslevis (change prefix or methods if needed)
if request.url.path.startswith("/reslevis/") and request.method in {"POST", "PUT", "DELETE", "PATCH"}:
body = await request.body() # raw body preserved
local_resp = await call_next(request) # local storage runs here
if request.method in {"POST", "PUT", "DELETE", "PATCH"} and _should_proxy(request.url.path):
body = await request.body()
local_resp = await call_next(request)
if local_resp.status_code >= 400:
return local_resp # stop if local failed
return local_resp
return await _forward_to_core(request, body)
return await call_next(request)



+ 110
- 4
routes/reslevis.py 查看文件

@@ -1,4 +1,6 @@
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Request
import httpx
import config_env
from typing import List

from schemas.reslevis import (
@@ -27,7 +29,38 @@ from logica_reslevis.tracker_zone import TrackerZoneJsonRepository

from security import get_current_user

router = APIRouter()
#CORE SYNC
CORE_BASE_URL = config_env.CORE_API_URL.rstrip("/")
CORE_TIMEOUT = 2.0 # secondi

async def sync_core_get(request: Request) -> None:
if request.method != "GET":
return

sync = CORE_GET_SYNC.get(request.url.path)
if sync is None:
return
repo, normalizer = sync

try:
async with httpx.AsyncClient(timeout=CORE_TIMEOUT) as client:
resp = await client.get(
f"{CORE_BASE_URL}{request.url.path}",
params=request.query_params,
)

if 200 <= resp.status_code < 300:
data = resp.json()
if isinstance(data, list):
if normalizer:
data = [normalizer(r) for r in data if isinstance(r, dict)]
repo._write_all(data) # aggiorna i file locali
except (httpx.RequestError, ValueError):
# CORE giù o risposta non valida -> uso il file locale
pass


router = APIRouter(dependencies=[Depends(sync_core_get)])

gateway_repo = GatewayJsonRepository()
building_repo = BuildingJsonRepository()
@@ -40,6 +73,79 @@ alarm_repo = AlarmJsonRepository()
track_repo = TrackJsonRepository()
tracker_zone_repo = TrackerZoneJsonRepository()

def _none_if_empty(v):
return None if v in ("", None, 0, "0") else v

def _str_or_none(v):
if v in ("", None):
return None
if isinstance(v, (int, float, bool)):
return str(v)
return v

def _uuid_list(values):
if values in ("", None):
return []
if isinstance(values, str):
values = [v for v in values.split(",") if v]
if isinstance(values, (list, tuple, set)):
cleaned = []
for v in values:
if isinstance(v, dict):
v = v.get("id") or v.get("uuid")
if v in ("", None, 0, "0"):
continue
cleaned.append(v)
return cleaned
return [values] if values not in ("", None, 0, "0") else []

def _normalize_gateway(row: dict) -> dict:
row = dict(row)
row["floor"] = _none_if_empty(row.get("floor"))
row["building"] = _none_if_empty(row.get("building"))
return row

def _normalize_tracker(row: dict) -> dict:
row = dict(row)
row["floor"] = _none_if_empty(row.get("floor"))
row["building"] = _none_if_empty(row.get("building"))
row["battery"] = _str_or_none(row.get("battery"))
row["temperature"] = _str_or_none(row.get("temperature"))
row["acceleration"] = _str_or_none(row.get("acceleration"))
row["heartRate"] = _str_or_none(row.get("heartRate"))
return row

def _normalize_track(row: dict) -> dict:
row = dict(row)
row["gateway"] = _none_if_empty(row.get("gateway"))
row["tracker"] = _none_if_empty(row.get("tracker"))
row["subject"] = _none_if_empty(row.get("subject"))
row["floor"] = _none_if_empty(row.get("floor"))
row["building"] = _none_if_empty(row.get("building"))
row["timestamp"] = _str_or_none(row.get("timestamp"))
row["type"] = _str_or_none(row.get("type"))
row["status"] = _str_or_none(row.get("status"))
row["gatewayMac"] = _str_or_none(row.get("gatewayMac"))
row["trackerMac"] = _str_or_none(row.get("trackerMac"))
row["subjectName"] = _str_or_none(row.get("subjectName"))
# signal resta float o None
row["signal"] = None if row.get("signal") in ("", None) else row.get("signal")
return row

def _normalize_zone(row: dict) -> dict:
row = dict(row)
row["floor"] = _none_if_empty(row.get("floor"))
row["building"] = _none_if_empty(row.get("building"))
row["groups"] = _uuid_list(row.get("groups"))
return row

CORE_GET_SYNC = {
"/reslevis/getGateways": (gateway_repo, _normalize_gateway),
"/reslevis/getZones": (zone_repo, _normalize_zone),
"/reslevis/getTrackers": (tracker_repo, _normalize_tracker),
"/reslevis/getTracks": (track_repo, _normalize_track),
}


@router.get(
"/getGateways",
@@ -103,10 +209,10 @@ def removeBuilding(building_id: str):
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
)

def getFloors():
return floor_repo.list()


@router.post("/postFloor", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postFloor(item: FloorItem):
floor_repo.add(item)
@@ -289,4 +395,4 @@ def updateSubject(item: SubjectItem):
@router.delete("/removeSubject/{subject_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeSubject(subject_id: str):
subject_repo.remove(subject_id)
return {"message": "OK"}
return {"message": "OK"}

Loading…
取消
儲存