monstersirenfetch/generic.go
Yonah 343a8c5f45
generic: provide configured encoder
This encoder emits data identical to upstream API response body.

Signed-off-by: Yonah <contrib@gensokyo.uk>
2025-09-18 04:53:12 +09:00

85 lines
1.8 KiB
Go

package monstersirenfetch
import (
"context"
"encoding/json"
"io"
"strconv"
"strings"
)
const (
APIPrefix = "https://monster-siren.hypergryph.com/api"
)
// Net represents an abstraction over the [net] package.
type Net interface {
// Get makes a get request to url and returns the response body.
// The caller must close the body after it finishes reading from it.
Get(ctx context.Context, url string) (body io.ReadCloser, err error)
}
// Response is a generic API response.
type Response[T any] struct {
Code int `json:"code"`
Message string `json:"msg"`
Data T `json:"data"`
}
// NullableString is a JSON string where its zero value behaves like null.
type NullableString string
func (s *NullableString) MarshalJSON() ([]byte, error) {
if *s == "" {
return []byte("null"), nil
}
return json.Marshal(string(*s))
}
func (s *NullableString) UnmarshalJSON(data []byte) (err error) {
var v *string
err = json.Unmarshal(data, &v)
if err == nil {
if v != nil {
*s = NullableString(*v)
} else {
*s = ""
}
}
return
}
// StringInt is a JSON string representing an integer.
type StringInt int
func (i *StringInt) String() (s string) {
s = strconv.Itoa(int(*i))
if len(s) <= 4 {
s = strings.Repeat("0", 4-len(s)) + s
} else if len(s) < 6 {
s = strings.Repeat("0", 6-len(s)) + s
}
return
}
func (i *StringInt) MarshalJSON() ([]byte, error) { return json.Marshal(i.String()) }
func (i *StringInt) UnmarshalJSON(data []byte) (err error) {
var v string
err = json.Unmarshal(data, &v)
if err == nil {
var n int
n, err = strconv.Atoi(v)
if err == nil {
*i = StringInt(n)
}
}
return
}
// NewEncoder returns a new encoder that writes to w, configured to match upstream API behaviour.
func NewEncoder(w io.Writer) *json.Encoder {
e := json.NewEncoder(w)
e.SetEscapeHTML(false)
return e
}