package main import ( "sort" "sync" ) // TargetInfo holds the display name and gRPC address of one collector target. type TargetInfo struct { Name string // collector --source value, falls back to addr until first snapshot Addr string // configured gRPC address } // TargetRegistry tracks addr → display name for all configured collectors. // Names default to the addr and are updated to the collector's --source value // when the first snapshot arrives. type TargetRegistry struct { mu sync.RWMutex names map[string]string // addr → current name } func NewTargetRegistry(addrs []string) *TargetRegistry { names := make(map[string]string, len(addrs)) for _, a := range addrs { names[a] = a // default until first snapshot } return &TargetRegistry{names: names} } // SetName updates the display name for addr (called when a snapshot arrives). func (r *TargetRegistry) SetName(addr, name string) { r.mu.Lock() r.names[addr] = name r.mu.Unlock() } // Targets returns all registered targets sorted by addr. func (r *TargetRegistry) Targets() []TargetInfo { r.mu.RLock() defer r.mu.RUnlock() out := make([]TargetInfo, 0, len(r.names)) for addr, name := range r.names { out = append(out, TargetInfo{Name: name, Addr: addr}) } sort.Slice(out, func(i, j int) bool { return out[i].Addr < out[j].Addr }) return out }