95 lines
2.1 KiB
Go
95 lines
2.1 KiB
Go
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)
|
|
}
|