package stats import ( "context" "strings" "lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope" ) // ReloadSourceIdentities aligns live JT808 candidates with the durable platform // keys used by backfill and daily statistics. A snapshot avoids a database // lookup per frame; a failed refresh leaves the last successful snapshot intact. func (w *Writer) ReloadSourceIdentities(ctx context.Context) (int, error) { rows, err := w.query.QueryContext(ctx, `SELECT source_ip,COALESCE(source_code,''),COALESCE(platform_name,''),source_kind FROM vehicle_data_source WHERE protocol='JT808'`) if err != nil { return 0, err } defer rows.Close() next := map[string]SourceIdentity{} for rows.Next() { var source SourceIdentity if err := rows.Scan(&source.SourceIP, &source.SourceCode, &source.PlatformName, &source.SourceKind); err != nil { return 0, err } source.Protocol = envelope.ProtocolJT808 source.SourceIP = NormalizeSourceIP(source.SourceIP) source.SourceCode = strings.TrimSpace(source.SourceCode) source.SourceKind = strings.ToUpper(strings.TrimSpace(source.SourceKind)) if source.SourceIP != "" && ((source.SourceKind == "PLATFORM" && source.SourceCode != "") || source.SourceKind == "DIRECT") { next[source.SourceIP] = source } } if err := rows.Err(); err != nil { return 0, err } w.mu.Lock() w.sourceIdentities = next w.mu.Unlock() return len(next), nil } func (w *Writer) withSourceIdentity(env envelope.FrameEnvelope) envelope.FrameEnvelope { if env.Protocol != envelope.ProtocolJT808 { return env } ip := NormalizeSourceIP(env.SourceEndpoint) w.mu.Lock() source, found := w.sourceIdentities[ip] w.mu.Unlock() if found { env.SourceCode = source.SourceCode env.SourceKind = source.SourceKind if strings.TrimSpace(source.PlatformName) != "" { env.PlatformName = source.PlatformName } } return env }