feat(platform): harden telemetry pipeline and unify Semi UI workspaces
This commit is contained in:
94
go/vehicle-gateway/internal/feichibridge/model.go
Normal file
94
go/vehicle-gateway/internal/feichibridge/model.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package feichibridge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var shanghai = time.FixedZone("Asia/Shanghai", 8*60*60)
|
||||
|
||||
type Vehicle struct {
|
||||
VehicleID string `json:"vehicleId"`
|
||||
VIN string `json:"vin"`
|
||||
OnlineStatus any `json:"onlineStatus"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
RuleTypeName string `json:"ruleTypeName"`
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
VehicleID string `json:"vehicleId"`
|
||||
VIN string `json:"vin"`
|
||||
DataItems map[string]string `json:"dataItems"`
|
||||
}
|
||||
|
||||
type Record map[string]string
|
||||
|
||||
type collectionEnvelope[T any] struct {
|
||||
Code any `json:"code"`
|
||||
Data []T `json:"data"`
|
||||
}
|
||||
|
||||
type objectEnvelope[T any] struct {
|
||||
Code any `json:"code"`
|
||||
Data T `json:"data"`
|
||||
}
|
||||
|
||||
type historySegment struct {
|
||||
Subdata []Record `json:"subdata"`
|
||||
}
|
||||
|
||||
func apiCodeOK(code any) bool {
|
||||
switch value := code.(type) {
|
||||
case nil:
|
||||
return true
|
||||
case float64:
|
||||
return value == 0 || value == 200
|
||||
case string:
|
||||
return value == "" || value == "0" || value == "200"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func recordTime(record Record) (time.Time, error) {
|
||||
for _, key := range []string{"2000", "9999", "dataTime", "updateTime", "time"} {
|
||||
if raw := strings.TrimSpace(record[key]); raw != "" {
|
||||
return parseSourceTime(raw)
|
||||
}
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("source record has no timestamp")
|
||||
}
|
||||
|
||||
func parseSourceTime(raw string) (time.Time, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
for _, layout := range []string{
|
||||
"2006-01-02 15:04:05",
|
||||
"2006-01-02T15:04:05",
|
||||
time.RFC3339Nano,
|
||||
} {
|
||||
if layout == time.RFC3339Nano {
|
||||
if parsed, err := time.Parse(layout, raw); err == nil {
|
||||
return parsed, nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
if parsed, err := time.ParseInLocation(layout, raw, shanghai); err == nil {
|
||||
return parsed, nil
|
||||
}
|
||||
}
|
||||
if unixMS, err := strconv.ParseInt(raw, 10, 64); err == nil {
|
||||
if unixMS < 10_000_000_000 {
|
||||
return time.Unix(unixMS, 0).In(shanghai), nil
|
||||
}
|
||||
return time.UnixMilli(unixMS).In(shanghai), nil
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("unsupported source timestamp %q", raw)
|
||||
}
|
||||
|
||||
func canonicalHash(record Record) string {
|
||||
encoded, _ := json.Marshal(record)
|
||||
return hashBytes(encoded)
|
||||
}
|
||||
Reference in New Issue
Block a user