feat: track jt808 registration identity
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
||||
@@ -50,6 +51,9 @@ func safeIdentifier(value string) bool {
|
||||
|
||||
func (r *MySQLResolver) Resolve(ctx context.Context, env envelope.FrameEnvelope) (envelope.FrameEnvelope, error) {
|
||||
if strings.TrimSpace(env.VIN) != "" {
|
||||
if err := r.trackJT808(ctx, env); err != nil {
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
candidates := CandidateKeys(env)
|
||||
@@ -72,9 +76,15 @@ func (r *MySQLResolver) Resolve(ctx context.Context, env envelope.FrameEnvelope)
|
||||
"value": candidate.Value,
|
||||
}
|
||||
env.EventID = env.StableEventID()
|
||||
if err := r.trackJT808(ctx, env); err != nil {
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
}
|
||||
if err := r.trackJT808(ctx, env); err != nil {
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
@@ -85,6 +95,81 @@ func (r *MySQLResolver) lookup(ctx context.Context, column string, value string)
|
||||
return vin, err
|
||||
}
|
||||
|
||||
func (r *MySQLResolver) trackJT808(ctx context.Context, env envelope.FrameEnvelope) error {
|
||||
if env.Protocol != envelope.ProtocolJT808 || strings.TrimSpace(env.Phone) == "" || strings.TrimSpace(env.MessageID) == "" {
|
||||
return nil
|
||||
}
|
||||
registration := mapValue(env.Parsed, "registration")
|
||||
authentication := mapValue(env.Parsed, "authentication")
|
||||
deviceID := firstNonEmpty(env.DeviceID, textValue(registration, "device_id"))
|
||||
plate := firstNonEmpty(env.Plate, textValue(registration, "plate"))
|
||||
vin := strings.TrimSpace(env.VIN)
|
||||
if vin == "" {
|
||||
vin = "unknown"
|
||||
}
|
||||
firstRegisteredAt := nilTime()
|
||||
latestRegisteredAt := nilTime()
|
||||
if env.MessageID == "0x0100" {
|
||||
firstRegisteredAt = "CURRENT_TIMESTAMP"
|
||||
latestRegisteredAt = "CURRENT_TIMESTAMP"
|
||||
}
|
||||
latestAuthenticatedAt := nilTime()
|
||||
if env.MessageID == "0x0102" {
|
||||
latestAuthenticatedAt = "CURRENT_TIMESTAMP"
|
||||
}
|
||||
|
||||
query := `INSERT INTO jt808_registration
|
||||
(phone, device_id, plate, vin, province, city, manufacturer, device_type, plate_color,
|
||||
auth_token, auth_imei, auth_software_version, source_endpoint,
|
||||
first_registered_at, latest_registered_at, latest_authenticated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ` + firstRegisteredAt + `, ` + latestRegisteredAt + `, ` + latestAuthenticatedAt + `)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
device_id = IF(VALUES(device_id) <> '', VALUES(device_id), device_id),
|
||||
plate = IF(VALUES(plate) <> '', VALUES(plate), plate),
|
||||
vin = IF(VALUES(vin) <> 'unknown', VALUES(vin), vin),
|
||||
province = IF(VALUES(province) <> '', VALUES(province), province),
|
||||
city = IF(VALUES(city) <> '', VALUES(city), city),
|
||||
manufacturer = IF(VALUES(manufacturer) <> '', VALUES(manufacturer), manufacturer),
|
||||
device_type = IF(VALUES(device_type) <> '', VALUES(device_type), device_type),
|
||||
plate_color = IF(VALUES(plate_color) <> '', VALUES(plate_color), plate_color),
|
||||
auth_token = IF(VALUES(auth_token) <> '', VALUES(auth_token), auth_token),
|
||||
auth_imei = IF(VALUES(auth_imei) <> '', VALUES(auth_imei), auth_imei),
|
||||
auth_software_version = IF(VALUES(auth_software_version) <> '', VALUES(auth_software_version), auth_software_version),
|
||||
source_endpoint = IF(VALUES(source_endpoint) <> '', VALUES(source_endpoint), source_endpoint),
|
||||
latest_seen_at = CURRENT_TIMESTAMP,
|
||||
first_registered_at = COALESCE(first_registered_at, VALUES(first_registered_at)),
|
||||
latest_registered_at = COALESCE(VALUES(latest_registered_at), latest_registered_at),
|
||||
latest_authenticated_at = COALESCE(VALUES(latest_authenticated_at), latest_authenticated_at)`
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
env.Phone,
|
||||
deviceID,
|
||||
plate,
|
||||
vin,
|
||||
textValue(registration, "province"),
|
||||
textValue(registration, "city"),
|
||||
textValue(registration, "manufacturer"),
|
||||
textValue(registration, "device_type"),
|
||||
textValue(registration, "plate_color"),
|
||||
textValue(authentication, "token"),
|
||||
textValue(authentication, "imei"),
|
||||
textValue(authentication, "software_version"),
|
||||
env.SourceEndpoint,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vin == "unknown" {
|
||||
return nil
|
||||
}
|
||||
_, err = r.db.ExecContext(ctx, `UPDATE IGNORE `+r.table+`
|
||||
SET
|
||||
phone = CASE WHEN (phone IS NULL OR phone = '') AND ? <> '' THEN ? ELSE phone END,
|
||||
device_id = CASE WHEN (device_id IS NULL OR device_id = '') AND ? <> '' THEN ? ELSE device_id END,
|
||||
plate = CASE WHEN (plate IS NULL OR plate = '') AND ? <> '' THEN ? ELSE plate END
|
||||
WHERE vin = ?`, env.Phone, env.Phone, deviceID, deviceID, plate, plate, vin)
|
||||
return err
|
||||
}
|
||||
|
||||
type CandidateKey struct {
|
||||
Column string
|
||||
Value string
|
||||
@@ -113,3 +198,40 @@ func CandidateKeys(env envelope.FrameEnvelope) []CandidateKey {
|
||||
add("vin", env.VehicleKeyHint)
|
||||
return out
|
||||
}
|
||||
|
||||
func mapValue(values map[string]any, key string) map[string]any {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
nested, _ := values[key].(map[string]any)
|
||||
return nested
|
||||
}
|
||||
|
||||
func textValue(values map[string]any, key string) string {
|
||||
if values == nil {
|
||||
return ""
|
||||
}
|
||||
value, ok := values[key]
|
||||
if !ok || value == nil {
|
||||
return ""
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
return strings.TrimSpace(typed)
|
||||
default:
|
||||
return strings.TrimSpace(fmt.Sprint(typed))
|
||||
}
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func nilTime() string {
|
||||
return "NULL"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user