qr-reader: reply Connection: close (fixes ~10s beep delay)
The reader sends Connection: keep-alive but only acts on the verdict (beep,
output) once the TCP socket closes. Fastify's default kept the connection alive,
so the reader waited out a ~10s keep-alive timeout before beeping — even though
the server replied in ~15ms. Every vendor demo replies Connection: close and
shuts the socket. Set reply.header('connection','close') on the QR endpoint.
Verified the header is now sent; symptom was correct accept/reject with a ~10s
lag before the beep.
This commit is contained in:
@@ -44,8 +44,14 @@ export async function qrReaderRoutes(
|
||||
|
||||
// No auth: the reader is a machine on the isolated device subnet and offers no
|
||||
// auth on its side. Public route, like the Dingtian input push.
|
||||
const handler = async (req: { query: ReaderQuery }) => {
|
||||
const handler = async (req: { query: ReaderQuery }, reply: import("fastify").FastifyReply) => {
|
||||
const q = req.query;
|
||||
// The reader sends `Connection: keep-alive` but only ACTS on our verdict (beep,
|
||||
// drive output) once the socket CLOSES — every vendor demo replies
|
||||
// `Connection: close` and shuts the socket. Without it the reader waits out a
|
||||
// ~10 s keep-alive timeout before beeping. So force-close the connection.
|
||||
// See wiki/sources/qrcode-sdk.md, entities/gee-qr-er80.md.
|
||||
reply.header("connection", "close");
|
||||
const cardid = (q.cardid ?? "").trim();
|
||||
const mjihao = q.mjihao != null ? Number(q.mjihao) : 0;
|
||||
const serial = (q.cjihao ?? "").trim();
|
||||
|
||||
@@ -111,3 +111,12 @@ enter its serial here.
|
||||
`status:1` 2-beep when the QR matches a permit/open session.
|
||||
- `output` is replied as `0` (Access). Confirm on hardware whether the reader needs `1`/`2` (WG26/34)
|
||||
to drive its access line, vs. `0`.
|
||||
|
||||
## ⚠️ Reply MUST set `Connection: close` (verified on hardware)
|
||||
|
||||
The reader sends `Connection: keep-alive` but **only acts on the verdict (beep/output) once the TCP
|
||||
socket CLOSES**. Fastify's default keeps the connection alive → the reader waits out a **~10 s
|
||||
keep-alive timeout before beeping**, even though the server replied in ~15 ms. Every vendor demo
|
||||
replies **`Connection: close`** and shuts the socket. Fix: the endpoint sets
|
||||
`reply.header("connection","close")`. Symptom if regressed: correct accept/reject but a ~10 s lag
|
||||
before the beep. (The request arrives fast; the delay is entirely the reader waiting for close.)
|
||||
|
||||
@@ -691,3 +691,12 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
[[dingtian-relay]] connected. NOT for production. Registered in the catalog.
|
||||
- To get a live accept: assign Stub barrier to the reader's lane + a permit whose QR = the scanned
|
||||
code → status:1 (2-beep) + logged pulseOpen.
|
||||
|
||||
## [2026-06-16] fix | QR reader 10s beep delay — reply must Connection: close
|
||||
- Live accept worked (status:1, pulseOpen, 2 beeps) but the beep came ~10 s LATE. Server responded
|
||||
in 14.7 ms; user confirmed request is fast, only the beep lags → delay is the READER, not us.
|
||||
- Cause: reader sends `Connection: keep-alive` but only ACTS on the verdict once the socket CLOSES;
|
||||
Fastify kept it alive → reader waited out a ~10 s keep-alive timeout. Every vendor demo replies
|
||||
`Connection: close` + shuts the socket.
|
||||
- Fix: endpoint sets `reply.header("connection","close")`. Verified the header is now sent.
|
||||
- Updated [[gee-qr-er80]] (⚠️ Connection: close requirement).
|
||||
|
||||
Reference in New Issue
Block a user