16 Commits

Author SHA1 Message Date
Sebastian Norling
d7cfee56a1 fix(event/stream): address round-2 review findings
Critical
  - Renew busy-loop on persistent failure: after a failed
    renewPullPoint, the loop re-read the (now in-past)
    GrantedTermination and nextRenewInterval floored to 1s, hammering
    the camera at 1 Hz until reconnect. nextRenewIntervalAfterError
    decouples the failure path from the stale grant and backs off
    at opts.RetryBackoff. renewLoop also routes through s.now() so
    test clocks can drive it deterministically.
  - Lost-update race on GrantedTermination: a renew result for an
    old subscription could overwrite the grant on a new one if
    attemptRecreate swapped pullPoint mid-flight. A generation
    counter on Stream tracks subscription rotation; the renew loop
    captures the generation before the SOAP call and discards the
    result if the subscription was rotated.
  - Credential leak when <Security> straddled the 64 KiB error cap:
    the non-greedy regex required a closing tag and missed the
    truncated case. wsseSecurityRE now matches close-tag-or-EOF.
    Belt-and-braces wssePasswordRE redacts <Password> elements
    outside any Security wrapper.
  - addHeaderChildren accepted well-formed-but-element-free input
    and produced a header-less request. Now errors out.

Important
  - Wrapper detection in buildRefParamsHeader was HasSuffix-based and
    misfired on children named *ReferenceParameters. Replaced with the
    unambiguous wrapper-only contract: input must be the full
    <*:ReferenceParameters> element returned by extractReferenceParameters.
  - Renamed SoapOption → SendSoapOption and WithHeader → WithSOAPHeader
    to disambiguate at call sites.
  - Renamed WithHeader's `xml` parameter to headerContent to avoid
    shadowing the encoding/xml package name.
  - Documented terminationTimeRE's "first match only" semantics so
    nobody re-uses it from PullMessages context where multiple
    TerminationTime elements appear.
  - goleak is now a direct require (go mod tidy).

Performance
  - Added gosoap.AddStringHeaderContents (plural) for multi-root
    header content. AddStringHeaderContent remains as-is for
    backwards compatibility with external consumers. Device.go's
    addHeaderChildren workaround is gone — one etree parse per
    SendSoapWithOptions call instead of two.

Migration
  - Device.go's own CallOnvifFunction and the three examples now
    call SendSoapWithOptions, modelling the canonical path.

Docs / tests
  - Trust-boundary warning on SendSoapWithHeader/Options godoc.
  - Comments on createPullPointResp/Alt explain why TerminationTime
    is intentionally omitted (renew timing fixtures).
  - New tests: digest retry strips WS-Security, duplicate
    WithSOAPHeader is last-wins, malformed TerminationTime yields
    zero, margin==base falls to base/2, empty SubscriptionReference
    yields empty ref params, Security straddling cap is redacted,
    bare Password redacted, wrapper-only contract is enforced.
2026-05-27 18:07:56 +02:00
Sebastian Norling
1ceef725ec fix(examples): secure credential handling and Errors-arm bug
Two findings from the resource/security and API reviews of the
streamtest example.

Credentials
-----------
* loadPassword resolves the camera password in order:
    1. ONVIF_PASSWORD environment variable (recommended).
    2. -password-file <path> (newline trimmed).
    3. Interactive prompt when nothing else is set.
* -password flag still works but now logs a WARNING that the value
  leaks into shell history and process listings. Documented as
  'INSECURE' in the flag help.
* Updated package godoc with a Credentials section.

Errors-arm bug
--------------
* Previous code: case e := <-s.Errors() with no ok check. When the
  Stream closed, this arm would spin on a closed channel printing
  '<nil>' forever (until ctx-done elsewhere unblocked it). Mirror
  the Events arm's ok pattern.
* Switched the error-log branch to inspect the typed errors added
  in the previous commit: ErrRecreateFailed gets a louder 'camera
  may be offline' log line; ErrPullFailed is a quieter
  'will retry' since the loop handles transient pull errors
  automatically.

Also prints '[after-reconnect]' on events carrying that flag so the
operator can see when the stream silently recovered a dropped
subscription — confirms the new observability surface is useful at
the CLI level.
2026-05-21 15:02:23 +02:00
Sebastian Norling
94572504fc style(examples): gofmt alignment for stream example Options literal 2026-05-21 14:58:48 +02:00
Sebastian Norling
fd71109514 refactor(event/stream): tighten public surface per v1 review
API-shape changes flagged as 'hard to reverse after v1' by the
architect reviewer. Acceptable to do now while no external code
imports the package; would be breaking later.

Surface tightening
------------------
* Decode unexported to decode. The Stream is the only intended caller;
  exposing the helper invited future API drift. Same-package tests
  still reach it.
* TopicFilter renamed to RawTopicFilter to signal that the value is
  fed verbatim into the SOAP envelope and is the 'advanced escape
  hatch', not the supported routing surface. Callers should normally
  leave it empty and rely on Classify.

Options zero-value policy clarified
-----------------------------------
* Field godoc on every numeric option now explicitly states 'zero
  means default' so the policy is local, not buried in
  withDefaults().
* New DisableReconnect bool — addresses the
  ReconnectAfterFailures=0-as-disable footgun the API reviewer flagged.
  Reader can no longer confuse 'unset, fallback to default' with 'opt
  out of reconnect'.
* BufferSize semantics extended: zero -> default (16), negative ->
  unbuffered (0), positive -> explicit size. Lets callers ask for
  back-pressure-only channels.

Default tuning
--------------
* MessageLimit default raised from 10 to 32. Busy AXIS cameras with
  several configured inputs / analytics rules can burst beyond 10
  per pull; the lower cap meant up to one PullTimeout of added
  latency for the queued overflow without saving anything
  meaningful. 32 covers observed bursts with no real overhead on
  quiet pulls.

Caller interface
----------------
* Doc comment now states the goroutine-safety contract Stream
  depends on (pull loop and renew loop call from separate
  goroutines). *onvif.Device satisfies it via http.Client.

Package documentation
---------------------
* doc.go rewritten as a real godoc landing page: usage snippet,
  invariants (channel close, Close idempotency, NewStream does I/O,
  buffer semantics), reconnect behaviour and AfterReconnect, and a
  pointer to topics.go for the classifier table. Replaces the
  earlier stub that referenced unimplemented identifiers.
2026-05-21 14:58:34 +02:00
Sebastian Norling
176e0d8f3c feat(examples): add event/stream CLI for live camera verification
Adds a small command at examples/event/stream that opens a real ONVIF
event stream against a camera and prints decoded events one per line.
Intended for verifying the classifier against actual hardware (AXIS in
particular) and as runnable documentation for new consumers of the
package — point it at a configured camera, trigger motion, watch the
events arrive.

Behaviour
---------
* Required flags: -xaddr, -username, -password (matches existing
  examples/event/* commands so anyone running the older subscribe /
  pullmessage demos already knows the shape).
* Optional -filter passes through to Options.TopicFilter; default
  empty so AXIS works out of the box.
* -duration N stops after N (default 0 = run until Ctrl-C).
* Prints kind/state/op/topic on each event plus source and data maps
  when present, so multi-item ONVIF payloads (AXIS AOA
  active+classType+confidence, DigitalInput InputToken+LogicalState)
  are visible without re-reading PullMessages SOAP.
* Errors channel surfaced to stderr via log; the stream auto-recovers
  per the reconnect logic in stream.go so transient errors do not
  terminate the demo.

Not part of any CI; not a production tool — this is a verification
harness.
2026-05-21 14:42:02 +02:00
Cedric Verstraeten
8902e4e789 upgrade onvif library 2023-12-18 20:16:21 +01:00
Cedric Verstraeten
71b6d48393 diz memory leak + import 2023-12-06 20:38:25 +01:00
Cedric Verstraeten
bb5a87b253 Merge remote-tracking branch 'upstream/master' 2023-12-06 19:45:28 +01:00
Jean-Francois Smigielski
72a3540cc3 Let the example code use the generated SDK methods
Also introduces zerolog for pretty traces and juju/errors to annotate the errors
and track their origin.
2022-05-11 10:05:57 +02:00
Jean-Francois Smigielski
6f1154fc4d ws-discovery: Return an error instead of printing & ignoring 2022-05-10 13:21:27 +02:00
cedricve
37d8a71395 rename imports 2021-06-04 21:51:49 +02:00
kikimor
51ae55e8a0 External httpClient support 2021-02-24 21:58:44 +05:00
Edward
dce0d0faad add an example by testing 2020-05-01 22:58:49 +08:00
Edward
928207d461 simple mod to github.com/use-go/onvif 2020-04-29 10:53:49 +08:00
Eamon
28cfd7c4d4 fix package using in current repository 2018-05-16 15:40:49 +08:00
yakovlevdmv
edeeac2935 WS-Security fixed to correspond YUNCH yc-110ar camera, examples folder added 2018-04-10 22:42:27 +03:00