package attributes import ( "errors" "fmt" "strings" "github.com/nspcc-dev/neofs-api-go/pkg/netmap" ) const ( pairSeparator = "/" keyValueSeparator = ":" ) var ( errEmptyChain = errors.New("empty attribute chain") errNonUniqueBucket = errors.New("attributes must contain unique keys") errUnexpectedKey = errors.New("attributes contain unexpected key") ) // ParseV2Attributes parses strings like "K1:V1/K2:V2/K3:V3" into netmap // attributes. func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute, error) { restricted := make(map[string]struct{}, len(excl)) for i := range excl { restricted[excl[i]] = struct{}{} } cache := make(map[string]*netmap.NodeAttribute, len(attrs)) for i := range attrs { line := strings.Trim(attrs[i], pairSeparator) chain := strings.Split(line, pairSeparator) if len(chain) == 0 { return nil, errEmptyChain } var parentKey string // backtrack parents in next pairs for j := range chain { pair := strings.Split(chain[j], keyValueSeparator) if len(pair) != 2 { return nil, fmt.Errorf("incorrect attribute pair %s", chain[j]) } key := pair[0] value := pair[1] if at, ok := cache[key]; ok && at.Value() != value { return nil, errNonUniqueBucket } if _, ok := restricted[key]; ok { return nil, errUnexpectedKey } attribute := netmap.NewNodeAttribute() attribute.SetKey(key) attribute.SetValue(value) if parentKey != "" { attribute.SetParentKeys(parentKey) } parentKey = key cache[key] = attribute } } result := make([]*netmap.NodeAttribute, 0, len(cache)) for _, v := range cache { result = append(result, v) } return result, nil }