package network import ( "errors" "fmt" "sort" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" ) // AddressGroup represents list of network addresses of the node. // // List is sorted by priority of use. type AddressGroup []Address // StringifyGroup returns concatenation of all addresses // from the AddressGroup. // // The result is order-dependent. func StringifyGroup(x AddressGroup) string { var s string iterateAllAddresses(x, func(addr Address) { s += addr.String() }) return s } // IterateAddresses iterates over all network addresses of the node. // // Breaks iterating on handler's true return. // // Handler should not be nil. func (x AddressGroup) IterateAddresses(f func(Address) bool) { for i := range x { if f(x[i]) { break } } } // iterateAllAddresses iterates over all network addresses of g // and passes each of them to f. func iterateAllAddresses(g AddressGroup, f func(Address)) { g.IterateAddresses(func(addr Address) bool { f(addr) return false }) } // Len returns number of addresses in AddressGroup. func (x AddressGroup) Len() int { return len(x) } // Less returns true if i-th address in AddressGroup supports TLS // and j-th one doesn't. func (x AddressGroup) Less(i, j int) bool { return x[i].IsTLSEnabled() && !x[j].IsTLSEnabled() } // Swap swaps i-th and j-th addresses in AddressGroup. func (x AddressGroup) Swap(i, j int) { x[i], x[j] = x[j], x[i] } // MultiAddressIterator is an interface of network address group. type MultiAddressIterator interface { // IterateAddresses must iterate over network addresses and pass each one // to the handler until it returns true. IterateAddresses(func(string) bool) // NumberOfAddresses must return number of addresses in group. NumberOfAddresses() int } // FromStringSlice forms AddressGroup from a string slice. // // Returns an error in the absence of addresses or if any of the addresses are incorrect. func (x *AddressGroup) FromStringSlice(addr []string) error { if len(addr) == 0 { return errors.New("missing network addresses") } res := make(AddressGroup, len(addr)) for i := range addr { var a Address if err := a.FromString(addr[i]); err != nil { return err // invalid format, ignore the whole field } res[i] = a } *x = res return nil } // FromIterator forms AddressGroup from MultiAddressIterator structure. // The result is sorted with sort.Sort. // // Returns an error in the absence of addresses or if any of the addresses are incorrect. func (x *AddressGroup) FromIterator(iter MultiAddressIterator) error { as := *x addrNum := iter.NumberOfAddresses() if addrNum <= 0 { return errors.New("missing network addresses") } if cap(as) >= addrNum { as = as[:0] } else { as = make(AddressGroup, 0, addrNum) } err := iterateParsedAddresses(iter, func(a Address) error { as = append(as, a) return nil }) if err == nil { sort.Sort(as) *x = as } return err } // iterateParsedAddresses parses each address from MultiAddressIterator and passes it to f // until 1st parsing failure or f's error. func iterateParsedAddresses(iter MultiAddressIterator, f func(s Address) error) (err error) { iter.IterateAddresses(func(s string) bool { var a Address err = a.FromString(s) if err != nil { err = fmt.Errorf("could not parse address from string: %w", err) return true } err = f(a) return err != nil }) return } // WriteToNodeInfo writes AddressGroup to netmap.NodeInfo structure. func WriteToNodeInfo(g AddressGroup, ni *netmap.NodeInfo) { num := g.Len() addrs := make([]string, 0, num) iterateAllAddresses(g, func(addr Address) { ni.SetNetworkEndpoints() addrs = append(addrs, addr.String()) }) ni.SetNetworkEndpoints(addrs...) } // Intersects checks if two AddressGroup have // at least one common address. func (x AddressGroup) Intersects(x2 AddressGroup) bool { for i := range x { for j := range x2 { if x[i].equal(x2[j]) { return true } } } return false }