feat(platform): summarize vehicle source status
This commit is contained in:
@@ -85,17 +85,44 @@ func (s *Service) VehicleDetail(ctx context.Context, vin string, protocol string
|
||||
if err != nil {
|
||||
return VehicleDetail{}, err
|
||||
}
|
||||
sourceStatus := vehicleSourceStatus(vehicles.Items, realtime.Items, history.Items, raw.Items, mileage.Items)
|
||||
sourceStatus = s.enrichVehicleSourceStatus(ctx, resolvedVIN, sourceStatus)
|
||||
return VehicleDetail{
|
||||
VIN: resolvedVIN,
|
||||
Identity: identity,
|
||||
Sources: vehicleSources(vehicles.Items, realtime.Items, raw.Items, mileage.Items),
|
||||
Realtime: realtime.Items,
|
||||
History: history,
|
||||
Raw: raw,
|
||||
Mileage: mileage,
|
||||
VIN: resolvedVIN,
|
||||
Identity: identity,
|
||||
Sources: sourceNames(sourceStatus),
|
||||
SourceStatus: sourceStatus,
|
||||
Realtime: realtime.Items,
|
||||
History: history,
|
||||
Raw: raw,
|
||||
Mileage: mileage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) enrichVehicleSourceStatus(ctx context.Context, vin string, statuses []VehicleSourceStatus) []VehicleSourceStatus {
|
||||
for index := range statuses {
|
||||
protocol := statuses[index].Protocol
|
||||
if protocol == "" {
|
||||
continue
|
||||
}
|
||||
if !statuses[index].HasHistory {
|
||||
query := url.Values{"vin": {vin}, "protocol": {protocol}, "limit": {"1"}}
|
||||
if page, err := s.store.HistoryLocationsFromTDengine(ctx, query); err == nil && len(page.Items) > 0 {
|
||||
statuses[index].HasHistory = true
|
||||
statuses[index].LastSeen = latestString(statuses[index].LastSeen, firstNonEmpty(page.Items[0].ServerTime, page.Items[0].DeviceTime))
|
||||
}
|
||||
}
|
||||
if !statuses[index].HasRaw {
|
||||
page, err := s.store.RawFrames(ctx, RawFrameQuery{VIN: vin, Protocol: protocol, Limit: 1})
|
||||
if err == nil && len(page.Items) > 0 {
|
||||
statuses[index].HasRaw = true
|
||||
statuses[index].LastSeen = latestString(statuses[index].LastSeen, firstNonEmpty(page.Items[0].ServerTime, page.Items[0].DeviceTime))
|
||||
}
|
||||
}
|
||||
}
|
||||
return statuses
|
||||
}
|
||||
|
||||
func resolveVehicleIdentity(keyword string, vehicles []VehicleRow) *VehicleRow {
|
||||
keyword = strings.TrimSpace(keyword)
|
||||
if keyword == "" {
|
||||
@@ -144,31 +171,83 @@ func (s *Service) OpsHealth(ctx context.Context) (OpsHealth, error) {
|
||||
return s.store.OpsHealth(ctx)
|
||||
}
|
||||
|
||||
func vehicleSources(vehicles []VehicleRow, realtime []RealtimeLocationRow, raw []RawFrameRow, mileage []DailyMileageRow) []string {
|
||||
seen := map[string]struct{}{}
|
||||
add := func(value string) {
|
||||
func vehicleSourceStatus(vehicles []VehicleRow, realtime []RealtimeLocationRow, history []HistoryLocationRow, raw []RawFrameRow, mileage []DailyMileageRow) []VehicleSourceStatus {
|
||||
statusByProtocol := map[string]*VehicleSourceStatus{}
|
||||
ensure := func(protocol string) *VehicleSourceStatus {
|
||||
protocol = strings.TrimSpace(protocol)
|
||||
if protocol == "" {
|
||||
return nil
|
||||
}
|
||||
if current := statusByProtocol[protocol]; current != nil {
|
||||
return current
|
||||
}
|
||||
current := &VehicleSourceStatus{Protocol: protocol}
|
||||
statusByProtocol[protocol] = current
|
||||
return current
|
||||
}
|
||||
setLastSeen := func(current *VehicleSourceStatus, value string) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
if current.LastSeen == "" || value > current.LastSeen {
|
||||
current.LastSeen = value
|
||||
}
|
||||
}
|
||||
for _, row := range vehicles {
|
||||
add(row.Protocol)
|
||||
if current := ensure(row.Protocol); current != nil {
|
||||
current.Online = current.Online || row.Online
|
||||
setLastSeen(current, row.LastSeen)
|
||||
}
|
||||
}
|
||||
for _, row := range realtime {
|
||||
add(row.Protocol)
|
||||
if current := ensure(row.Protocol); current != nil {
|
||||
current.HasRealtime = true
|
||||
setLastSeen(current, row.LastSeen)
|
||||
}
|
||||
}
|
||||
for _, row := range history {
|
||||
if current := ensure(row.Protocol); current != nil {
|
||||
current.HasHistory = true
|
||||
setLastSeen(current, firstNonEmpty(row.ServerTime, row.DeviceTime))
|
||||
}
|
||||
}
|
||||
for _, row := range raw {
|
||||
add(row.Protocol)
|
||||
if current := ensure(row.Protocol); current != nil {
|
||||
current.HasRaw = true
|
||||
setLastSeen(current, firstNonEmpty(row.ServerTime, row.DeviceTime))
|
||||
}
|
||||
}
|
||||
for _, row := range mileage {
|
||||
add(row.Source)
|
||||
if current := ensure(row.Source); current != nil {
|
||||
current.HasMileage = true
|
||||
setLastSeen(current, row.Date)
|
||||
}
|
||||
}
|
||||
out := make([]string, 0, len(seen))
|
||||
for source := range seen {
|
||||
out = append(out, source)
|
||||
out := make([]VehicleSourceStatus, 0, len(statusByProtocol))
|
||||
for _, current := range statusByProtocol {
|
||||
out = append(out, *current)
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].Protocol < out[j].Protocol })
|
||||
return out
|
||||
}
|
||||
|
||||
func latestString(left string, right string) string {
|
||||
left = strings.TrimSpace(left)
|
||||
right = strings.TrimSpace(right)
|
||||
if left == "" {
|
||||
return right
|
||||
}
|
||||
if right == "" || left >= right {
|
||||
return left
|
||||
}
|
||||
return right
|
||||
}
|
||||
|
||||
func sourceNames(statuses []VehicleSourceStatus) []string {
|
||||
out := make([]string, 0, len(statuses))
|
||||
for _, status := range statuses {
|
||||
out = append(out, status.Protocol)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user