package properties import ( "bufio" "bytes" "errors" "io" "badat.dev/maeqtt/v2/mqtt/types" ) type Property interface { id() int parse(r *bufio.Reader) error write(w io.Writer) error hasValue() bool } func findMatchingProp(props []Property, id int) *Property { for _, prop := range props { if prop.id() == id { return (&prop) } } return nil } func ParseProperties(r *bufio.Reader, props []Property) error { propLen, err := types.DecodeVariableByteInt(r) if err != nil { return err } limitReader := io.LimitReader(r, int64(propLen)) r = bufio.NewReader(limitReader) for { propId, err := r.ReadByte() if err != nil { if err == io.EOF { break } else { return err } } prop := findMatchingProp(props, int(propId)) if prop == nil { return errors.New("Malformed packet invalid propid") } err = (*prop).parse(r) if err != nil { return err } } return nil } func WriteProps(w io.Writer, props []Property) error { buf := bytes.NewBuffer([]byte{}) for _, p := range props { if p.hasValue() { buf.Write([]byte{byte(p.id())}) err := p.write(buf) if err != nil { return err } } } return types.WriteDataWithVarIntLen(w, buf.Bytes()) } type KVPair struct { key string value string } type UserProperty struct { values []KVPair } func (*UserProperty) id() int { return 38 } func (u *UserProperty) parse(r *bufio.Reader) error { key, err := types.DecodeUTF8String(r) if err != nil { return err } value, err := types.DecodeUTF8String(r) if err != nil { return err } u.values = append(u.values, KVPair{ key: key, value: value, }) return nil } func (u *UserProperty) write(w io.Writer) error { for _, k := range u.values { err := types.WriteUTF8String(w, k.key) if err != nil { return err } err = types.WriteUTF8String(w, k.value) if err != nil { return err } } return nil } func (u *UserProperty) hasValue() bool { return len(u.values) > 0 }