- Adopt an opinionated Event.ID policy across sources: - use upstream-provided ID when available - otherwise derive a stable ID from Source:EffectiveAt (RFC3339Nano, UTC) - fall back to Source:EmittedAt when EffectiveAt is unavailable - Add common/id helper to centralize ID selection logic and keep sources consistent - Simplify common event construction by collapsing SingleRawEventAt/SingleRawEvent into a single explicit SingleRawEvent helper (emittedAt passed in) - Update NWS/Open-Meteo/OpenWeather observation sources to: - compute EffectiveAt first - generate IDs via the shared helper - build envelopes via the unified SingleRawEvent helper - Improve determinism and dedupe-friendliness without changing schemas or payloads
55 lines
1.3 KiB
Go
55 lines
1.3 KiB
Go
// FILE: ./internal/sources/common/event.go
|
|
package common
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/ejr/feedkit/event"
|
|
)
|
|
|
|
// SingleRawEvent constructs, validates, and returns a slice containing exactly one event.
|
|
//
|
|
// This removes repetitive "event envelope ceremony" from individual sources.
|
|
// Sources remain responsible for:
|
|
// - fetching bytes (raw payload)
|
|
// - choosing Schema (raw schema identifier)
|
|
// - computing Event.ID and (optional) EffectiveAt
|
|
//
|
|
// emittedAt is explicit so callers can compute IDs using the same timestamp (or
|
|
// so tests can provide a stable value).
|
|
func SingleRawEvent(
|
|
kind event.Kind,
|
|
sourceName string,
|
|
schema string,
|
|
id string,
|
|
emittedAt time.Time,
|
|
effectiveAt *time.Time,
|
|
payload any,
|
|
) ([]event.Event, error) {
|
|
if emittedAt.IsZero() {
|
|
emittedAt = time.Now().UTC()
|
|
} else {
|
|
emittedAt = emittedAt.UTC()
|
|
}
|
|
|
|
e := event.Event{
|
|
ID: id,
|
|
Kind: kind,
|
|
Source: sourceName,
|
|
EmittedAt: emittedAt,
|
|
EffectiveAt: effectiveAt,
|
|
|
|
// RAW schema (normalizer matches on this).
|
|
Schema: schema,
|
|
|
|
// Raw payload (usually json.RawMessage). Normalizer will decode and map to canonical model.
|
|
Payload: payload,
|
|
}
|
|
|
|
if err := e.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []event.Event{e}, nil
|
|
}
|