refactor(go): map realtime fields to semantic names

This commit is contained in:
lingniu
2026-07-03 13:51:57 +08:00
parent c359930009
commit e1bf2d72e1
4 changed files with 306 additions and 51 deletions

View File

@@ -36,10 +36,7 @@ func (r *Repository) FastUpdate(ctx context.Context, env envelope.FrameEnvelope)
if vehicleKey == "" || strings.HasSuffix(vehicleKey, ":unknown") {
return nil
}
if err := r.setKV(ctx, vin, env, env.Parsed); err != nil {
return err
}
return r.setOnline(ctx, vehicleKey, vin, env.Protocol, env.ReceivedAtMS, env.SourceEndpoint)
return r.setFastProjection(ctx, vehicleKey, vin, env)
}
func (r *Repository) Update(ctx context.Context, env envelope.FrameEnvelope) error {
@@ -234,6 +231,7 @@ func (r *Repository) setKV(ctx context.Context, vin string, env envelope.FrameEn
"protocol": string(env.Protocol),
"vin": vin,
"source_endpoint": env.SourceEndpoint,
"field_mapping": realtimeFieldMappingVersion,
}
pipe := r.client.Pipeline()
pipe.HSet(ctx, realtimeKVValuesKey(env.Protocol, vin), values)
@@ -243,6 +241,73 @@ func (r *Repository) setKV(ctx context.Context, vin string, env envelope.FrameEn
return err
}
func (r *Repository) setFastProjection(ctx context.Context, vehicleKey string, vin string, env envelope.FrameEnvelope) error {
rows := realtimeKVFields(env, env.Parsed)
values, types := realtimeKVMaps(rows)
eventTimeMS := eventTimeOrReceivedMS(env)
offlineAfterMS := env.ReceivedAtMS + r.cfg.ttl().Milliseconds()
online := OnlineStatus{
VehicleKey: vehicleKey,
VIN: vin,
Protocol: env.Protocol,
Online: true,
LastSeenMS: env.ReceivedAtMS,
OfflineAfterMS: offlineAfterMS,
SourceEndpoint: env.SourceEndpoint,
Protocols: []envelope.Protocol{env.Protocol},
TTLSeconds: int64(r.cfg.ttl().Seconds()),
}
payload, err := json.Marshal(online)
if err != nil {
return err
}
meta := map[string]any{
"event_time_ms": strconv.FormatInt(eventTimeMS, 10),
"received_at_ms": strconv.FormatInt(env.ReceivedAtMS, 10),
"event_id": env.StableEventID(),
"protocol": string(env.Protocol),
"vin": vin,
"source_endpoint": env.SourceEndpoint,
"field_mapping": realtimeFieldMappingVersion,
}
state := map[string]any{
"vehicle_key": vehicleKey,
"vin": vin,
"protocol": string(env.Protocol),
"online": strconv.FormatBool(true),
"last_seen_ms": strconv.FormatInt(env.ReceivedAtMS, 10),
"offline_after_ms": strconv.FormatInt(offlineAfterMS, 10),
"ttl_seconds": strconv.FormatInt(int64(r.cfg.ttl().Seconds()), 10),
"source_endpoint": env.SourceEndpoint,
}
pipe := r.client.Pipeline()
if len(values) > 0 {
pipe.HSet(ctx, realtimeKVValuesKey(env.Protocol, vin), values)
pipe.HSet(ctx, realtimeKVTypesKey(env.Protocol, vin), types)
pipe.HSet(ctx, realtimeKVMetaKey(env.Protocol, vin), meta)
}
pipe.Set(ctx, onlineKey(env.Protocol, vin), payload, r.cfg.ttl())
pipe.HSet(ctx, onlineStateKey(env.Protocol, vin), state)
pipe.ZAdd(ctx, "vehicle:last_seen", redis.Z{Score: float64(env.ReceivedAtMS), Member: onlineMember(env.Protocol, vin)})
pipe.SAdd(ctx, realtimeIndexKey(env.Protocol), vin)
_, err = pipe.Exec(ctx)
return err
}
func realtimeKVMaps(rows []RealtimeKVField) (map[string]any, map[string]any) {
values := make(map[string]any, len(rows))
types := make(map[string]any, len(rows))
for _, row := range rows {
field := realtimeKVFieldPath(row.Domain, row.Field)
if field == "" {
continue
}
values[field] = row.Value
types[field] = row.ValueType
}
return values, types
}
func (r *Repository) setOnline(ctx context.Context, vehicleKey string, vin string, protocol envelope.Protocol, lastSeenMS int64, sourceEndpoint string) error {
if protocol == "" {
return nil