platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func normalizeTransportClientsState(st transportClientsState, forceRebalance bool) (transportClientsState, bool) {
|
||||
changed := false
|
||||
st.Version = transportStateVersion
|
||||
if st.Items == nil {
|
||||
st.Items = nil
|
||||
return st, false
|
||||
}
|
||||
|
||||
out := make([]TransportClient, 0, len(st.Items))
|
||||
byID := map[string]int{}
|
||||
for _, raw := range st.Items {
|
||||
it := raw
|
||||
id := sanitizeID(it.ID)
|
||||
if id == "" {
|
||||
changed = true
|
||||
continue
|
||||
}
|
||||
if it.ID != id {
|
||||
it.ID = id
|
||||
changed = true
|
||||
}
|
||||
ifaceID := normalizeTransportIfaceID(it.IfaceID)
|
||||
if it.IfaceID != ifaceID {
|
||||
it.IfaceID = ifaceID
|
||||
changed = true
|
||||
}
|
||||
|
||||
kind := normalizeTransportKind(it.Kind)
|
||||
if kind == "" {
|
||||
kind = TransportClientSingBox
|
||||
changed = true
|
||||
}
|
||||
it.Kind = kind
|
||||
if normCfg, cfgChanged := normalizeTransportClientConfig(it.Kind, it.Config); cfgChanged {
|
||||
it.Config = normCfg
|
||||
changed = true
|
||||
}
|
||||
|
||||
if strings.TrimSpace(it.Name) == "" {
|
||||
it.Name = id
|
||||
changed = true
|
||||
}
|
||||
|
||||
status := normalizeTransportStatus(it.Status)
|
||||
if status != it.Status {
|
||||
it.Status = status
|
||||
changed = true
|
||||
}
|
||||
|
||||
if !equalStringSlices(it.Capabilities, defaultTransportCapabilities(it.Kind)) {
|
||||
it.Capabilities = defaultTransportCapabilities(it.Kind)
|
||||
changed = true
|
||||
}
|
||||
if normRuntime, runtimeChanged := normalizeTransportRuntimeStored(it.Runtime, it.Kind, it.Config); runtimeChanged {
|
||||
it.Runtime = normRuntime
|
||||
changed = true
|
||||
}
|
||||
|
||||
if strings.TrimSpace(it.Health.LastCheck) == "" {
|
||||
if strings.TrimSpace(it.UpdatedAt) != "" {
|
||||
it.Health.LastCheck = it.UpdatedAt
|
||||
} else {
|
||||
it.Health.LastCheck = time.Now().UTC().Format(time.RFC3339)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
|
||||
if idx, ok := byID[it.ID]; ok {
|
||||
// Keep deterministic winner for duplicate IDs.
|
||||
if preferTransportClient(it, out[idx]) {
|
||||
out[idx] = it
|
||||
}
|
||||
changed = true
|
||||
continue
|
||||
}
|
||||
byID[it.ID] = len(out)
|
||||
out = append(out, it)
|
||||
}
|
||||
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
|
||||
usedTables := map[string]struct{}{}
|
||||
for i := range out {
|
||||
if strings.TrimSpace(out[i].RoutingTable) == "" {
|
||||
continue
|
||||
}
|
||||
wantTable := normalizeTransportRoutingTable(out[i].RoutingTable, transportRoutingTableForID(out[i].ID))
|
||||
if out[i].RoutingTable != wantTable {
|
||||
out[i].RoutingTable = wantTable
|
||||
changed = true
|
||||
}
|
||||
usedTables[wantTable] = struct{}{}
|
||||
}
|
||||
for i := range out {
|
||||
if strings.TrimSpace(out[i].RoutingTable) != "" {
|
||||
continue
|
||||
}
|
||||
wantTable := transportRoutingTableForIDUnique(out[i].ID, usedTables)
|
||||
if out[i].RoutingTable != wantTable {
|
||||
out[i].RoutingTable = wantTable
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
norm, allocChanged := reconcileTransportAllocations(out, forceRebalance)
|
||||
if allocChanged {
|
||||
changed = true
|
||||
}
|
||||
st.Items = norm
|
||||
return st, changed
|
||||
}
|
||||
|
||||
func normalizeTransportStatus(st TransportClientStatus) TransportClientStatus {
|
||||
switch st {
|
||||
case TransportClientStarting, TransportClientUp, TransportClientDegraded, TransportClientDown:
|
||||
return st
|
||||
default:
|
||||
return TransportClientDown
|
||||
}
|
||||
}
|
||||
|
||||
func equalStringSlices(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func preferTransportClient(cand, cur TransportClient) bool {
|
||||
cu := strings.TrimSpace(cand.UpdatedAt)
|
||||
ou := strings.TrimSpace(cur.UpdatedAt)
|
||||
if cu != ou {
|
||||
if cu == "" {
|
||||
return false
|
||||
}
|
||||
if ou == "" {
|
||||
return true
|
||||
}
|
||||
return cu > ou
|
||||
}
|
||||
if cand.Enabled != cur.Enabled {
|
||||
return cand.Enabled
|
||||
}
|
||||
return strings.TrimSpace(cand.Name) > strings.TrimSpace(cur.Name)
|
||||
}
|
||||
Reference in New Issue
Block a user