package attributes import ( "fmt" "strings" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" ) const keyValueSeparator = ":" // ReadNodeAttributes parses node attributes from list of string in "Key:Value" format // and writes them into netmap.NodeInfo instance. Supports escaped symbols // "\:", "\/" and "\\". func ReadNodeAttributes(dst *netmap.NodeInfo, attrs []string) error { cache := make(map[string]struct{}, len(attrs)) for i := range attrs { line := replaceEscaping(attrs[i], false) // replaced escaped symbols with non-printable symbols k, v, found := strings.Cut(line, keyValueSeparator) if !found { return fmt.Errorf("wrong format for node attribute: '%s'", attrs[i]) } _, ok := cache[k] if ok { return fmt.Errorf("duplicated keys %s", k) } cache[k] = struct{}{} // replace non-printable symbols with escaped symbols without escape character k = replaceEscaping(k, true) v = replaceEscaping(v, true) if k == "" { return fmt.Errorf("empty key in node attribute: '%s'", attrs[i]) } else if v == "" { return fmt.Errorf("empty value in node attribute: '%s'", attrs[i]) } dst.SetAttribute(k, v) } return nil } func replaceEscaping(target string, rollback bool) (s string) { const escChar = `\` var ( oldKVSep = escChar + keyValueSeparator oldEsc = escChar + escChar newKVSep = string(uint8(2)) newEsc = string(uint8(3)) ) if rollback { oldKVSep, oldEsc = newKVSep, newEsc newKVSep = keyValueSeparator newEsc = escChar } s = strings.ReplaceAll(target, oldEsc, newEsc) s = strings.ReplaceAll(s, oldKVSep, newKVSep) return }