fix: throttle jt808 registration touches

This commit is contained in:
lingniu
2026-07-02 10:24:44 +08:00
parent a66f765e16
commit e7d024405a
6 changed files with 111 additions and 29 deletions

View File

@@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"strings"
"sync"
"time"
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
)
@@ -21,11 +23,22 @@ func (NoopResolver) Resolve(_ context.Context, env envelope.FrameEnvelope) (enve
}
type MySQLResolver struct {
db *sql.DB
table string
db *sql.DB
table string
locationTouchInterval time.Duration
touchMu sync.Mutex
locationTouches map[string]time.Time
}
type MySQLResolverOptions struct {
LocationTouchInterval time.Duration
}
func NewMySQLResolver(db *sql.DB, table string) *MySQLResolver {
return NewMySQLResolverWithOptions(db, table, MySQLResolverOptions{})
}
func NewMySQLResolverWithOptions(db *sql.DB, table string, opts MySQLResolverOptions) *MySQLResolver {
if db == nil {
panic("identity db must not be nil")
}
@@ -33,7 +46,16 @@ func NewMySQLResolver(db *sql.DB, table string) *MySQLResolver {
if table == "" || !safeIdentifier(table) {
table = "vehicle_identity_binding"
}
return &MySQLResolver{db: db, table: table}
interval := opts.LocationTouchInterval
if interval <= 0 {
interval = 10 * time.Minute
}
return &MySQLResolver{
db: db,
table: table,
locationTouchInterval: interval,
locationTouches: map[string]time.Time{},
}
}
func safeIdentifier(value string) bool {
@@ -50,6 +72,7 @@ func safeIdentifier(value string) bool {
}
func (r *MySQLResolver) Resolve(ctx context.Context, env envelope.FrameEnvelope) (envelope.FrameEnvelope, error) {
env.Phone = normalizePhone(env.Phone)
if strings.TrimSpace(env.VIN) != "" {
if err := r.trackJT808(ctx, env); err != nil {
return env, err
@@ -99,6 +122,9 @@ func (r *MySQLResolver) trackJT808(ctx context.Context, env envelope.FrameEnvelo
if env.Protocol != envelope.ProtocolJT808 || strings.TrimSpace(env.Phone) == "" || strings.TrimSpace(env.MessageID) == "" {
return nil
}
if env.MessageID != "0x0100" && env.MessageID != "0x0102" && !r.shouldTouchJT808Location(env) {
return nil
}
registration := mapValue(env.Parsed, "registration")
authentication := mapValue(env.Parsed, "authentication")
deviceID := firstNonEmpty(env.DeviceID, textValue(registration, "device_id"))
@@ -170,6 +196,25 @@ WHERE vin = ?`, env.Phone, env.Phone, deviceID, deviceID, plate, plate, vin)
return err
}
func (r *MySQLResolver) shouldTouchJT808Location(env envelope.FrameEnvelope) bool {
if env.MessageID != "0x0200" {
return false
}
phone := normalizePhone(env.Phone)
if phone == "" {
return false
}
now := time.Now()
r.touchMu.Lock()
defer r.touchMu.Unlock()
last, ok := r.locationTouches[phone]
if ok && now.Sub(last) < r.locationTouchInterval {
return false
}
r.locationTouches[phone] = now
return true
}
type CandidateKey struct {
Column string
Value string
@@ -189,16 +234,21 @@ func CandidateKeys(env envelope.FrameEnvelope) []CandidateKey {
}
out = append(out, CandidateKey{Column: column, Value: value})
}
add("phone", env.Phone)
if trimmed := strings.TrimLeft(strings.TrimSpace(env.Phone), "0"); trimmed != "" {
add("phone", trimmed)
}
add("phone", normalizePhone(env.Phone))
add("device_id", env.DeviceID)
add("plate", env.Plate)
add("vin", env.VehicleKeyHint)
return out
}
func normalizePhone(phone string) string {
trimmed := strings.TrimLeft(strings.TrimSpace(phone), "0")
if trimmed == "" {
return strings.TrimSpace(phone)
}
return trimmed
}
func mapValue(values map[string]any, key string) map[string]any {
if values == nil {
return nil