Skip to content

Commit b1d5055

Browse files
committed
better catch errors in qr code generation
1 parent 638fe25 commit b1d5055

File tree

2 files changed

+66
-18
lines changed

2 files changed

+66
-18
lines changed

backend/automatic_walk_time_tables/map_downloader/create_map.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -335,23 +335,35 @@ def create_mapfish_query(
335335
point_layers.append(point_layer)
336336

337337
qr_code_string = build_qr_code_image_string(self.uuid)
338+
if not qr_code_string:
339+
# try 3 times more
340+
for _ in range(3):
341+
time.sleep(0.5)
342+
qr_code_string = build_qr_code_image_string(self.uuid)
343+
if qr_code_string:
344+
break
345+
346+
attributes = {
347+
"scale": "Massstab: 1:" + f"{map_scaling:,}".replace(",", "'"),
348+
"map": {
349+
"center": center,
350+
"scale": map_scaling,
351+
"dpi": 250,
352+
"pdfA": True,
353+
"projection": "EPSG:2056",
354+
"rotation": 0,
355+
"layers": point_layers + ([path_layer] + map_layers),
356+
},
357+
}
358+
359+
# Only include qr_code when we actually received a valid QR image
360+
if qr_code_string:
361+
attributes["qr_code"] = qr_code_string
338362

339363
query_json = {
340364
"layout": "A4 landscape",
341365
"outputFormat": "pdf",
342-
"attributes": {
343-
"scale": "Massstab: 1:" + f"{map_scaling:,}".replace(",", "'"),
344-
"qr_code": qr_code_string,
345-
"map": {
346-
"center": center,
347-
"scale": map_scaling,
348-
"dpi": 250,
349-
"pdfA": True,
350-
"projection": "EPSG:2056",
351-
"rotation": 0,
352-
"layers": point_layers + ([path_layer] + map_layers),
353-
},
354-
},
366+
"attributes": attributes,
355367
}
356368

357369
return query_json

backend/automatic_walk_time_tables/utils/qr.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,55 @@
11
import requests
22
import os
33
import base64
4+
import logging
5+
from http.client import IncompleteRead
46

57

68
def build_qr_code_image_string(uuid, raw: bool = False):
79
backend_domain = os.environ["BACKEND_DOMAIN"]
810
clear_url = f"{backend_domain}/gpx/{uuid}.gpx"
911
b64_url = base64.b64encode(clear_url.encode("ascii")).decode("ascii")
1012
final_url = "https://swisstopo.app/u/" + b64_url
11-
r = requests.post(
12-
"https://backend.qr.cevi.tools/png",
13-
json={"text": final_url},
14-
)
13+
try:
14+
r = requests.post(
15+
"https://backend.qr.cevi.tools/png",
16+
json={"text": final_url},
17+
)
18+
except requests.exceptions.RequestException:
19+
logging.exception("Failed to request QR backend for UUID=%s URL=%s", uuid, "https://backend.qr.cevi.tools/png")
20+
return ""
21+
except IncompleteRead:
22+
logging.exception("IncompleteRead while requesting QR backend for UUID=%s", uuid)
23+
return ""
24+
25+
def _is_image(content: bytes, content_type: str | None) -> bool:
26+
if not content:
27+
return False
28+
if content_type and content_type.startswith("image/"):
29+
return True
30+
# Check common magic bytes for PNG, JPEG, GIF
31+
if content.startswith(b"\x89PNG\r\n\x1a\n"):
32+
return True
33+
if content.startswith(b"\xff\xd8\xff"):
34+
return True
35+
if content[:6] in (b"GIF87a", b"GIF89a"):
36+
return True
37+
return False
38+
1539
if r.status_code == 200:
1640
qr_code_bytes = r.content
1741

42+
content_type = r.headers.get("Content-Type") if hasattr(r, "headers") else None
43+
44+
if not _is_image(qr_code_bytes, content_type):
45+
logging.debug(
46+
"QR backend returned non-image content for UUID=%s content_type=%s content_len=%s",
47+
uuid,
48+
content_type,
49+
len(qr_code_bytes) if qr_code_bytes is not None else 0,
50+
)
51+
return ""
52+
1853
if raw:
1954
# if raw, only return the qr code image bytes
2055
return qr_code_bytes
@@ -30,4 +65,5 @@ def build_qr_code_image_string(uuid, raw: bool = False):
3065
return data_url
3166

3267
else:
33-
return "" # TODO: does this work?
68+
logging.debug("QR backend returned status %s for UUID=%s", r.status_code, uuid)
69+
return "" # no QR code

0 commit comments

Comments
 (0)