diff --git a/pkg/telemetry/streamer.go b/pkg/telemetry/streamer.go index 32bd0e91..b2c1341b 100644 --- a/pkg/telemetry/streamer.go +++ b/pkg/telemetry/streamer.go @@ -34,6 +34,10 @@ type streamingClient struct { // referenceTime is the reference point provided in the ACMI data. referenceTime time.Time + // referenceTimeSet tracks whether a ReferenceTime property has been received. It must not be + // replaced by referenceTime.IsZero() because 0001-01-01T00:00:00Z is a valid reference time + // used by some ACMI recorders (e.g. DCS2ACMI) and is also Go's zero time.Time value. + referenceTimeSet bool // referencePoint is the reference point provided in the ACMI data. referencePoint orb.Point // cursorTime is the current frame time, computed by adding the current time frame to the reference time. @@ -333,7 +337,7 @@ func (c *streamingClient) handleTimeFrame(line string) error { if err != nil { return fmt.Errorf("error parsing time frame: %w", err) } - if c.referenceTime.IsZero() { + if !c.referenceTimeSet { return errors.New("time frame received before reference time") } c.cursorTime = c.referenceTime.Add(offset) @@ -353,6 +357,7 @@ func (c *streamingClient) updateGlobalObject(update *objects.Update) error { return fmt.Errorf("error parsing reference time: %w", err) } c.referenceTime = referenceTime + c.referenceTimeSet = true if c.cursorTime.IsZero() { c.cursorTime = c.referenceTime } @@ -450,6 +455,7 @@ func (c *streamingClient) reset() { defer c.lock.Unlock() c.referenceTime = time.Time{} + c.referenceTimeSet = false c.referencePoint = orb.Point{} c.cursorTime = time.Time{} c.state = map[uint64]*objects.Object{} diff --git a/pkg/telemetry/streamer_test.go b/pkg/telemetry/streamer_test.go index 736bfaf4..934b2827 100644 --- a/pkg/telemetry/streamer_test.go +++ b/pkg/telemetry/streamer_test.go @@ -6,10 +6,41 @@ import ( "testing" "time" + "github.com/dharmab/goacmi/v2/parsing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +// TestHandleLineAcceptsZeroReferenceTime verifies that a zero-valued +// ReferenceTime (0001-01-01T00:00:00Z) is accepted and does not cause +// subsequent time frames to be rejected. This is regression test for +// a case that sometimes happens on Lima Kilo. +func TestHandleLineAcceptsZeroReferenceTime(t *testing.T) { + t.Parallel() + + const timeFrame = "#62754967308.46" // Observed value from eu.limakilo.net sometimes + lines := []string{ + "FileType=text/acmi/tacview", + "FileVersion=2.2", + "0,ReferenceTime=0001-01-01T00:00:00Z", + "0,ReferenceLongitude=30", + "0,ReferenceLatitude=30", + timeFrame, + } + + client := newStreamingClient(time.Second) + reader := bufio.NewReader(strings.NewReader(strings.Join(lines, "\n") + "\n")) + for range lines { + line, err := readACMILine(reader) + require.NoError(t, err) + require.NoError(t, client.handleLine(line)) + } + + offset, err := parsing.ParseTimeFrame(timeFrame) + require.NoError(t, err) + assert.Equal(t, time.Time{}.Add(offset), client.Time()) +} + func TestReadACMILineContinuationPreservesNextRecord(t *testing.T) { t.Parallel()