2023-12-21 06:28:53 +00:00
|
|
|
package domain
|
|
|
|
|
|
|
|
import (
|
2024-02-06 07:11:05 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/base64"
|
2023-12-21 06:28:53 +00:00
|
|
|
"net/url"
|
2024-02-06 07:11:05 +00:00
|
|
|
"strings"
|
2023-12-21 06:28:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func parseURL(rawURL string) (*url.URL, error) {
|
|
|
|
u, err := url.ParseRequestURI(rawURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, InvalidURLError{
|
|
|
|
URL: rawURL,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
}
|
2024-02-06 07:11:05 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
cursorSeparator = ","
|
|
|
|
cursorKeyValueSeparator = "="
|
|
|
|
)
|
|
|
|
|
2024-02-07 07:17:47 +00:00
|
|
|
func encodeCursor(s [][2]string) string {
|
|
|
|
if len(s) == 0 {
|
2024-02-06 07:11:05 +00:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2024-02-07 07:17:47 +00:00
|
|
|
n := len(cursorSeparator) * (len(s) - 1)
|
|
|
|
for _, el := range s {
|
|
|
|
n += len(el[0]) + len(el[1]) + len(cursorKeyValueSeparator)
|
2024-02-06 07:11:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
b.Grow(n)
|
|
|
|
|
2024-02-07 07:17:47 +00:00
|
|
|
for _, el := range s {
|
2024-02-06 07:11:05 +00:00
|
|
|
if b.Len() > 0 {
|
|
|
|
_, _ = b.WriteString(cursorSeparator)
|
|
|
|
}
|
|
|
|
|
2024-02-07 07:17:47 +00:00
|
|
|
_, _ = b.WriteString(el[0])
|
2024-02-06 07:11:05 +00:00
|
|
|
_, _ = b.WriteString(cursorKeyValueSeparator)
|
2024-02-07 07:17:47 +00:00
|
|
|
_, _ = b.WriteString(el[1])
|
2024-02-06 07:11:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return base64.StdEncoding.EncodeToString(b.Bytes())
|
|
|
|
}
|
|
|
|
|
2024-02-07 07:17:47 +00:00
|
|
|
const (
|
|
|
|
encodedCursorMinLength = 1
|
|
|
|
encodedCursorMaxLength = 1000
|
|
|
|
)
|
|
|
|
|
2024-02-06 07:11:05 +00:00
|
|
|
func decodeCursor(s string) (map[string]string, error) {
|
2024-02-07 07:17:47 +00:00
|
|
|
if err := validateStringLen(s, encodedCursorMinLength, encodedCursorMaxLength); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-02-06 07:11:05 +00:00
|
|
|
decodedBytes, err := base64.StdEncoding.DecodeString(s)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrInvalidCursor
|
|
|
|
}
|
|
|
|
decoded := string(decodedBytes)
|
|
|
|
|
|
|
|
kvs := strings.Split(decoded, cursorSeparator)
|
|
|
|
|
|
|
|
m := make(map[string]string, len(kvs))
|
|
|
|
|
|
|
|
for _, kv := range kvs {
|
|
|
|
k, v, found := strings.Cut(kv, cursorKeyValueSeparator)
|
|
|
|
if !found {
|
|
|
|
return nil, ErrInvalidCursor
|
|
|
|
}
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
}
|