package rest import ( "fmt" "io" "reflect" "git.ali33.ru/fcg-xvii/go-tools/json" ) func prefixFieldName(prefix, fieldName string) string { if len(prefix) > 0 { return fmt.Sprintf("%s.%s", prefix, fieldName) } return fieldName } // конверторы // Int64ToBytes упаковывает int64 в срез байтов заданной длины func Int64ToBytes(num int64, byteCount int) []byte { bytes := make([]byte, byteCount) for i := 0; i < byteCount; i++ { shift := uint((byteCount - 1 - i) * 8) bytes[i] = byte(num >> shift) } return bytes } // BytesToInt64 конвертирует срез байтов в int64 func BytesToInt64(bytes []byte) int64 { var num int64 for _, b := range bytes { num = (num << 8) | int64(b) } return num } // ioError возвращает ошибку ввода выввода func ioError(field string, err error) IErrorArgs { return NewError( "ErrIO", json.Map{ "field": field, "error": err.Error(), }, ) } // чтение // ReadBuf считывает срез заданного колличества байт и возвращает его func ReadBuf(r io.Reader, size int, field string) ([]byte, IErrorArgs) { buf := make([]byte, size) if _, err := r.Read(buf); err != nil { return nil, ioError(field, err) } return buf, nil } // ReadBufSize считывает размер байтового среза, затем сам срез и возвращает его. // lenSize - количество байтов, которыми описывается размер основного среза (см. ReadInt64) func ReadBufSize(r io.Reader, lenSize int, field string) ([]byte, IErrorArgs) { var size int64 if err := ReadInt64(r, lenSize, field+"_size", &size); err != nil { return nil, err } buf, err := ReadBuf(r, int(size), field) return buf, err } // ReadInt64 Считывает срез заданного размера, который конвертируется в число типа int64. // size - размер среза (может быть от 1 до 8 байт). // Результат записывается в значение указателя result func ReadInt64(r io.Reader, size int, field string, result *int64) IErrorArgs { buf := make([]byte, size) if _, err := r.Read(buf); err != nil { return ioError(field, err) } *result = BytesToInt64(buf) return nil } // ReadString считывает строку (длина строки, затем строку), см. ReadBufSize func ReadString(r io.Reader, lenSize int, field string, result *string) IErrorArgs { strBuf, err := ReadBufSize(r, lenSize, field) if err != nil { return err } *result = string(strBuf) return nil } // ReadByte считывает 1 байт func ReadByte(r io.Reader, field string, result *byte) IErrorArgs { buf, err := ReadBuf(r, 1, field) if err != nil { return err } *result = buf[0] return nil } // запись // WriteBuf записывает срез байтов func WriteBuf(w io.Writer, buf []byte, field string) IErrorArgs { if _, err := w.Write(buf); err != nil { return ioError(field, err) } return nil } // WriteInt64 конвертирует число типа int64 в срез заданного размера и записывает его func WriteInt64(w io.Writer, val int64, size int, field string) IErrorArgs { buf := Int64ToBytes(val, size) return WriteBuf(w, buf, field) } // WriteString записывает строку в поток. // Сначала записывается размер строки (lenSize - количество байт в срезе размера). // Далее строка конвертируется в байтовый срез и записывается в поток func WriteString(w io.Writer, val, field string, lenSize int) IErrorArgs { // длина if err := WriteInt64(w, int64(len(val)), lenSize, field+"_size"); err != nil { return err } // строка if len(val) == 0 { return nil } return WriteBuf(w, []byte(val), field) } // WriteBuf записывает 1 байт в поток func WriteByte(w io.Writer, val byte, field string) IErrorArgs { return WriteBuf(w, []byte{val}, field) } // WriteBufSize записывает срез байтов в поток. // Сначала записывается размер среза (lenSize - количество байт в срезе размера). // Далее в поток записывается сам срез func WriteBufSize(w io.Writer, val []byte, lenSize int, field string) IErrorArgs { // длина if err := WriteInt64(w, int64(len(val)), lenSize, field+"_size"); err != nil { return err } // буфер return WriteBuf(w, val, field) } // ObjectFieldKeys позволяет рекурсивно получить список вложенных объектов запроса для предварительного формирования их в контексте ответа func ObjectFieldKeys(l []any) (res json.Map) { res = make(json.Map) t := reflect.TypeOf(res) for _, v := range l { rv := reflect.ValueOf(v) if reflect.ValueOf(v).Kind() == reflect.Map { if rv.CanConvert(t) { m := rv.Convert(t).Interface().(json.Map) if name := m.String("name", ""); len(name) > 0 { res[name] = ObjectFieldKeys(m.Slice("fields", []any{})) } } } } return }