Files
zoneminder/web
Isaac ConnorandClaude Opus 5 cbd68bb323 fix: bind the EventStream status poll to the connkey it belongs to
Montage review created 86 stream connkeys in five minutes while only two of
them were ever polled, and each stream painted a single frame before being
replaced about 1.3s later.

The status poll for a connkey whose zms had exited returned result=Error,
recover() restarted the stream under a new connkey, and the reply already
queued for the old one arrived afterwards and restarted the new stream too.
Every restart painted its first frame, which reset consecutiveErrors and
recoveryDelay in img.onload, so the backoff never grew and the attempt limit
was never reached.

- Tag each ajax/stream.php exchange with the connkey it was issued for and
  ignore a reply, success or failure, once that connkey has been replaced.
  stream.php does not echo the connkey back, so the client tracks it.
- Restart only on reason=no_socket, the one class that means zms is gone,
  matching streamErrorIsFatal() in MonitorStream.js. The helper is duplicated
  as EventStream.errorIsFatal() because montagereview.php does not load
  MonitorStream.js.
- Start the poll timer next to the src that created the connkey instead of in
  img.onload, which is not a dependable per-restart signal for a
  multipart/x-mixed-replace img, and let the first query wait a full interval
  so a stream that is still starting is not read as a missing socket.
- Reset the recovery counters only on a successful status reply, so the
  exponential backoff and the attempt limit both work.

Also stop appending a second '?' to UrlToZMS, which already carries
'?monitor=N', so the logs no longer show monitor=24?source=event.

tests/js/eventstream-connkey.test.js covers the stale-reply rules, the fatal
classification and the URL separator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YEe1M3PWVMqYWihUeAa5N
2026-08-27 22:39:45 -04:00
..
…
…

Modern ZoneMinder Skin

This web frontend to ZoneMinder is a complete rewrite of the classic frontend, based on CakePHP.