refactor: refactor to adapt new custom json marshaler

This commit is contained in:
yusing 2025-04-16 14:39:26 +08:00
parent cdfc9d553b
commit c2b606e63e
43 changed files with 232 additions and 189 deletions

View file

@ -1,7 +1,6 @@
package handler_test
import (
"encoding/json"
"net"
"net/http"
"net/http/httptest"
@ -9,6 +8,8 @@ import (
"strconv"
"testing"
"github.com/yusing/go-proxy/pkg/json"
"github.com/stretchr/testify/require"
"github.com/yusing/go-proxy/agent/pkg/agent"
"github.com/yusing/go-proxy/agent/pkg/handler"

View file

@ -4,7 +4,6 @@ import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
@ -15,6 +14,8 @@ import (
"strings"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/net/gphttp"

View file

@ -5,12 +5,13 @@ import (
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/golang-jwt/jwt/v5"
"github.com/yusing/go-proxy/internal/common"

View file

@ -1,11 +1,12 @@
package auth
import (
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/golang-jwt/jwt/v5"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/gperr"

View file

@ -2,13 +2,14 @@ package auth
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/yusing/go-proxy/pkg/json"
. "github.com/yusing/go-proxy/internal/utils/testing"
"golang.org/x/crypto/bcrypt"
)

View file

@ -1,9 +1,10 @@
package certapi
import (
"encoding/json"
"net/http"
"github.com/yusing/go-proxy/pkg/json"
config "github.com/yusing/go-proxy/internal/config/types"
)

View file

@ -2,10 +2,11 @@ package dockerapi
import (
"context"
"encoding/json"
"net/http"
"sort"
"github.com/yusing/go-proxy/pkg/json"
dockerSystem "github.com/docker/docker/api/types/system"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/utils/strutils"
@ -13,8 +14,8 @@ import (
type dockerInfo dockerSystem.Info
func (d *dockerInfo) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
func (d *dockerInfo) MarshalJSONTo(buf []byte) []byte {
return json.MarshalTo(map[string]any{
"name": d.Name,
"version": d.ServerVersion,
"containers": map[string]int{
@ -25,8 +26,8 @@ func (d *dockerInfo) MarshalJSON() ([]byte, error) {
},
"images": d.Images,
"n_cpu": d.NCPU,
"memory": strutils.FormatByteSizeWithUnit(d.MemTotal),
})
"memory": strutils.FormatByteSize(d.MemTotal),
}, buf)
}
func DockerInfo(w http.ResponseWriter, r *http.Request) {

View file

@ -2,10 +2,11 @@ package dockerapi
import (
"context"
"encoding/json"
"net/http"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/coder/websocket"
"github.com/coder/websocket/wsjson"
"github.com/yusing/go-proxy/agent/pkg/agent"

View file

@ -1,12 +1,12 @@
package v1
import (
"encoding/json"
"io"
"net/http"
"github.com/yusing/go-proxy/internal/homepage"
"github.com/yusing/go-proxy/internal/net/gphttp"
"github.com/yusing/go-proxy/pkg/json"
)
const (

View file

@ -1,13 +1,14 @@
package v1
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"github.com/yusing/go-proxy/pkg/json"
_ "embed"
"github.com/yusing/go-proxy/agent/pkg/agent"

View file

@ -1,11 +1,12 @@
package query
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/yusing/go-proxy/pkg/json"
v1 "github.com/yusing/go-proxy/internal/api/v1"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/gperr"

View file

@ -1,9 +1,10 @@
package homepage
import (
"encoding/json"
"strings"
"github.com/yusing/go-proxy/pkg/json"
config "github.com/yusing/go-proxy/internal/config/types"
"github.com/yusing/go-proxy/internal/utils"
)
@ -42,7 +43,7 @@ func (cfg *ItemConfig) GetOverride(alias string) *ItemConfig {
return overrideConfigInstance.GetOverride(alias, cfg)
}
func (item *Item) MarshalJSON() ([]byte, error) {
func (item *Item) MarshalJSONTo(buf []byte) []byte {
var url *string
if !strings.ContainsRune(item.Alias, '.') {
godoxyCfg := config.GetInstance().Value()
@ -55,7 +56,7 @@ func (item *Item) MarshalJSON() ([]byte, error) {
} else {
url = &item.Alias
}
return json.Marshal(map[string]any{
return json.MarshalTo(map[string]any{
"show": item.Show,
"alias": item.Alias,
"provider": item.Provider,
@ -66,7 +67,7 @@ func (item *Item) MarshalJSON() ([]byte, error) {
"description": item.Description,
"sort_order": item.SortOrder,
"widget_config": item.WidgetConfig,
})
}, buf)
}
func (c Homepage) Add(item *Item) {

View file

@ -1,10 +1,11 @@
package homepage
import (
"encoding/json"
"sync"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/task"

View file

@ -1,12 +1,13 @@
package homepage
import (
"encoding/json"
"io"
"net/http"
"sync"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/lithammer/fuzzysearch/fuzzy"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/logging"

View file

@ -1,8 +1,9 @@
package period
import (
"encoding/json"
"time"
"github.com/yusing/go-proxy/pkg/json"
)
type Entries[T any] struct {
@ -48,11 +49,11 @@ func (e *Entries[T]) Get() []*T {
return res
}
func (e *Entries[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
func (e *Entries[T]) MarshalJSONTo(buf []byte) []byte {
return json.MarshalTo(map[string]any{
"entries": e.Get(),
"interval": e.interval,
})
}, buf)
}
func (e *Entries[T]) UnmarshalJSON(data []byte) error {

View file

@ -2,7 +2,6 @@ package period
import (
"context"
"encoding/json"
"fmt"
"net/url"
"os"
@ -15,6 +14,7 @@ import (
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/utils/atomic"
"github.com/yusing/go-proxy/pkg/json"
)
type (

View file

@ -0,0 +1,71 @@
package period
import (
"context"
"net/http"
"net/url"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/yusing/go-proxy/pkg/json"
)
func (p *Poller[T, AggregateT]) Test(t *testing.T, query url.Values) {
t.Helper()
for range 3 {
require.NoError(t, p.testPoll())
}
t.Run("periods", func(t *testing.T) {
assert.NoError(t, p.testMarshalPeriods(query))
})
t.Run("no period", func(t *testing.T) {
assert.NoError(t, p.testMarshalNoPeriod())
})
}
func (p *Poller[T, AggregateT]) testPeriod(period string, query url.Values) (any, error) {
query.Set("period", period)
return p.getRespData(&http.Request{URL: &url.URL{RawQuery: query.Encode()}})
}
func (p *Poller[T, AggregateT]) testPoll() error {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
data, err := p.poll(ctx, p.lastResult.Load())
if err != nil {
return err
}
for _, period := range p.period.Entries {
period.Add(time.Now(), data)
}
p.lastResult.Store(data)
return nil
}
func (p *Poller[T, AggregateT]) testMarshalPeriods(query url.Values) error {
for period := range p.period.Entries {
data, err := p.testPeriod(string(period), query)
if err != nil {
return err
}
_, err = json.Marshal(data)
if err != nil {
return err
}
}
return nil
}
func (p *Poller[T, AggregateT]) testMarshalNoPeriod() error {
data, err := p.getRespData(&http.Request{URL: &url.URL{}})
if err != nil {
return err
}
_, err = json.Marshal(data)
if err != nil {
return err
}
return nil
}

View file

@ -3,7 +3,6 @@ package systeminfo
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
@ -20,6 +19,7 @@ import (
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/metrics/period"
"github.com/yusing/go-proxy/pkg/json"
)
// json tags are left for tests
@ -55,7 +55,7 @@ type (
DownloadSpeed float64 `json:"download_speed"`
}
Sensors []sensors.TemperatureStat
Aggregated []map[string]any
Aggregated = json.MapSlice[any]
)
type SystemInfo struct {
@ -295,8 +295,8 @@ func (s *SystemInfo) collectSensorsInfo(ctx context.Context) error {
}
// explicitly implement MarshalJSON to avoid reflection
func (s *SystemInfo) MarshalJSON() ([]byte, error) {
b := bytes.NewBuffer(make([]byte, 0, 1024))
func (s *SystemInfo) MarshalJSONTo(buf []byte) []byte {
b := bytes.NewBuffer(buf)
b.WriteRune('{')
@ -315,7 +315,7 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
// memory
b.WriteString(`,"memory":`)
if s.Memory != nil {
b.WriteString(fmt.Sprintf(
b.Write(fmt.Appendf(nil,
`{"total":%d,"available":%d,"used":%d,"used_percent":%s}`,
s.Memory.Total,
s.Memory.Available,
@ -329,13 +329,13 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
// disk
b.WriteString(`,"disks":`)
if len(s.Disks) > 0 {
b.WriteString("{")
b.WriteRune('{')
first := true
for device, disk := range s.Disks {
if !first {
b.WriteRune(',')
}
b.WriteString(fmt.Sprintf(
b.Write(fmt.Appendf(nil,
`"%s":{"device":%q,"path":%q,"fstype":%q,"total":%d,"free":%d,"used":%d,"used_percent":%s}`,
device,
device,
@ -362,7 +362,7 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
if !first {
b.WriteRune(',')
}
b.WriteString(fmt.Sprintf(
b.Write(fmt.Appendf(nil,
`"%s":{"name":%q,"read_bytes":%d,"write_bytes":%d,"read_speed":%s,"write_speed":%s,"iops":%d}`,
name,
name,
@ -382,7 +382,7 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
// network
b.WriteString(`,"network":`)
if s.Network != nil {
b.WriteString(fmt.Sprintf(
b.Write(fmt.Appendf(nil,
`{"bytes_sent":%d,"bytes_recv":%d,"upload_speed":%s,"download_speed":%s}`,
s.Network.BytesSent,
s.Network.BytesRecv,
@ -396,13 +396,13 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
// sensors
b.WriteString(`,"sensors":`)
if len(s.Sensors) > 0 {
b.WriteString("{")
b.WriteRune('{')
first := true
for _, sensor := range s.Sensors {
if !first {
b.WriteRune(',')
}
b.WriteString(fmt.Sprintf(
b.Write(fmt.Appendf(nil,
`%q:{"name":%q,"temperature":%s,"high":%s,"critical":%s}`,
sensor.SensorKey,
sensor.SensorKey,
@ -418,7 +418,7 @@ func (s *SystemInfo) MarshalJSON() ([]byte, error) {
}
b.WriteRune('}')
return []byte(b.String()), nil
return b.Bytes()
}
func (s *Sensors) UnmarshalJSON(data []byte) error {
@ -560,43 +560,3 @@ func aggregate(entries []*SystemInfo, query url.Values) (total int, result Aggre
}
return len(aggregated), aggregated
}
func (result Aggregated) MarshalJSON() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, 1024))
buf.WriteByte('[')
i := 0
n := len(result)
for _, entry := range result {
buf.WriteRune('{')
j := 0
m := len(entry)
for k, v := range entry {
buf.WriteByte('"')
buf.WriteString(k)
buf.WriteByte('"')
buf.WriteByte(':')
switch v := v.(type) {
case float64:
buf.WriteString(strconv.FormatFloat(v, 'f', 2, 64))
case uint64:
buf.WriteString(strconv.FormatUint(v, 10))
case int64:
buf.WriteString(strconv.FormatInt(v, 10))
default:
panic(fmt.Sprintf("unexpected type: %T", v))
}
if j != m-1 {
buf.WriteByte(',')
}
j++
}
buf.WriteByte('}')
if i != n-1 {
buf.WriteByte(',')
}
i++
}
buf.WriteByte(']')
return buf.Bytes(), nil
}

View file

@ -1,15 +1,23 @@
package systeminfo
import (
"encoding/json"
"net/url"
"reflect"
"testing"
"github.com/shirou/gopsutil/v4/sensors"
. "github.com/yusing/go-proxy/internal/utils/testing"
"github.com/yusing/go-proxy/pkg/json"
)
func TestPoller(t *testing.T) {
for _, query := range allQueries {
t.Run(query, func(t *testing.T) {
Poller.Test(t, url.Values{"aggregate": []string{query}})
})
}
}
func TestExcludeDisks(t *testing.T) {
tests := []struct {
name string
@ -191,8 +199,7 @@ func TestSerialize(t *testing.T) {
for _, query := range allQueries {
t.Run(query, func(t *testing.T) {
_, result := aggregate(entries, url.Values{"aggregate": []string{query}})
s, err := result.MarshalJSON()
ExpectNoError(t, err)
s := result.MarshalJSONTo(nil)
var v []map[string]any
ExpectNoError(t, json.Unmarshal(s, &v))
ExpectEqual(t, len(v), len(result))
@ -206,31 +213,3 @@ func TestSerialize(t *testing.T) {
})
}
}
func BenchmarkJSONMarshal(b *testing.B) {
entries := make([]*SystemInfo, b.N)
for i := range b.N {
entries[i] = testInfo
}
queries := map[string]Aggregated{}
for _, query := range allQueries {
_, result := aggregate(entries, url.Values{"aggregate": []string{query}})
queries[query] = result
}
b.ReportAllocs()
b.ResetTimer()
b.Run("optimized", func(b *testing.B) {
for b.Loop() {
for _, query := range allQueries {
_, _ = queries[query].MarshalJSON()
}
}
})
b.Run("json", func(b *testing.B) {
for b.Loop() {
for _, query := range allQueries {
_, _ = json.Marshal([]map[string]any(queries[query]))
}
}
})
}

View file

@ -0,0 +1,22 @@
package uptime
import (
"fmt"
"github.com/yusing/go-proxy/internal/watcher/health"
)
type Status struct {
Status health.Status
Latency int64
Timestamp int64
}
type RouteStatuses map[string][]*Status
func (s *Status) MarshalJSONTo(buf []byte) []byte {
return fmt.Appendf(buf,
`{"status":"%s","latency":"%d","timestamp":"%d"}`,
s.Status, s.Latency, s.Timestamp,
)
}

View file

@ -2,7 +2,6 @@ package uptime
import (
"context"
"encoding/json"
"net/url"
"sort"
"time"
@ -13,20 +12,15 @@ import (
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/route/routes/routequery"
"github.com/yusing/go-proxy/internal/watcher/health"
"github.com/yusing/go-proxy/pkg/json"
)
type (
StatusByAlias struct {
Map map[string]*routequery.HealthInfoRaw `json:"statuses"`
Timestamp int64 `json:"timestamp"`
Map json.Map[*routequery.HealthInfoRaw] `json:"statuses"`
Timestamp int64 `json:"timestamp"`
}
Status struct {
Status health.Status `json:"status"`
Latency int64 `json:"latency"`
Timestamp int64 `json:"timestamp"`
}
RouteStatuses map[string][]*Status
Aggregated []map[string]any
Aggregated = json.MapSlice[any]
)
var Poller = period.NewPoller("uptime", getStatuses, aggregateStatuses)
@ -124,7 +118,3 @@ func (rs RouteStatuses) aggregate(limit int, offset int) Aggregated {
}
return result
}
func (result Aggregated) MarshalJSON() ([]byte, error) {
return json.Marshal([]map[string]any(result))
}

View file

@ -0,0 +1,10 @@
package uptime
import (
"net/url"
"testing"
)
func TestPoller(t *testing.T) {
Poller.Test(t, url.Values{"limit": []string{"1"}})
}

View file

@ -194,6 +194,6 @@ func (l *AccessLogger) write(data []byte) {
if err != nil {
l.handleErr(err)
} else {
logging.Debug().Msg("access log flushed to " + l.io.Name())
logging.Trace().Msg("access log flushed to " + l.io.Name())
}
}

View file

@ -2,13 +2,14 @@ package accesslog_test
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"testing"
"time"
"github.com/yusing/go-proxy/pkg/json"
. "github.com/yusing/go-proxy/internal/net/gphttp/accesslog"
"github.com/yusing/go-proxy/internal/task"
. "github.com/yusing/go-proxy/internal/utils/testing"

View file

@ -2,13 +2,14 @@ package accesslog
import (
"bytes"
"encoding/json"
"net"
"net/http"
"net/url"
"strconv"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/logging"
)

View file

@ -2,11 +2,12 @@ package gphttp
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/logging"
)

View file

@ -2,11 +2,12 @@ package gphttp
import (
"context"
"encoding/json"
"errors"
"net/http"
"syscall"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
)

View file

@ -12,7 +12,6 @@ import (
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/net/gphttp"
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
"github.com/yusing/go-proxy/internal/utils"
)
func warnNoMatchDomains() {
@ -95,7 +94,7 @@ func WriteText(r *http.Request, conn *websocket.Conn, msg string) bool {
func DynamicJSONHandler[ResultType any](w http.ResponseWriter, r *http.Request, getter func() ResultType, interval time.Duration) {
if httpheaders.IsWebsocket(r.Header) {
Periodic(w, r, interval, func(conn *websocket.Conn) error {
return wsjson.Write(r.Context(), conn, utils.ToJSONObject(getter()))
return wsjson.Write(r.Context(), conn, getter())
})
} else {
gphttp.RespondJSON(w, r, getter())

View file

@ -1,12 +1,13 @@
package middleware
import (
"encoding/json"
"net/http"
"reflect"
"sort"
"strings"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/logging"
gphttp "github.com/yusing/go-proxy/internal/net/gphttp"
@ -158,12 +159,12 @@ func (m *Middleware) String() string {
return m.name
}
func (m *Middleware) MarshalJSON() ([]byte, error) {
return json.MarshalIndent(map[string]any{
func (m *Middleware) MarshalJSONTo(buf []byte) []byte {
return json.MarshalTo(map[string]any{
"name": m.name,
"options": m.impl,
"priority": m.priority,
}, "", " ")
}, buf)
}
func (m *Middleware) ModifyRequest(next http.HandlerFunc, w http.ResponseWriter, r *http.Request) {

View file

@ -2,9 +2,10 @@ package middleware
import (
_ "embed"
"encoding/json"
"testing"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/gperr"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
@ -16,7 +17,7 @@ func TestBuild(t *testing.T) {
errs := gperr.NewBuilder("")
middlewares := BuildMiddlewaresFromYAML("", testMiddlewareCompose, errs)
ExpectNoError(t, errs.Error())
Must(json.MarshalIndent(middlewares, "", " "))
json.Marshal(middlewares)
// t.Log(string(data))
// TODO: test
}

View file

@ -3,12 +3,13 @@ package middleware
import (
"bytes"
_ "embed"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"net/url"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"

View file

@ -2,7 +2,8 @@ package notif
import (
"bytes"
"encoding/json"
"github.com/yusing/go-proxy/pkg/json"
)
func formatMarkdown(extras LogFields) string {

View file

@ -2,11 +2,12 @@ package notif
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/yusing/go-proxy/pkg/json"
"github.com/gotify/server/v2/model"
"github.com/rs/zerolog"
)

View file

@ -2,12 +2,13 @@ package notif
import (
_ "embed"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/yusing/go-proxy/pkg/json"
"github.com/yusing/go-proxy/internal/gperr"
)
@ -101,10 +102,7 @@ func (webhook *Webhook) makeRespError(resp *http.Response) error {
}
func (webhook *Webhook) MakeBody(logMsg *LogMessage) (io.Reader, error) {
title, err := json.Marshal(logMsg.Title)
if err != nil {
return nil, err
}
title := json.String(logMsg.Title)
fields, err := formatDiscord(logMsg.Extras)
if err != nil {
return nil, err
@ -115,13 +113,10 @@ func (webhook *Webhook) MakeBody(logMsg *LogMessage) (io.Reader, error) {
} else {
color = logMsg.Color.DecString()
}
message, err := json.Marshal(formatMarkdown(logMsg.Extras))
if err != nil {
return nil, err
}
message := json.String(formatMarkdown(logMsg.Extras))
plTempl := strings.NewReplacer(
"$title", string(title),
"$message", string(message),
"$title", title,
"$message", message,
"$fields", fields,
"$color", color,
)

View file

@ -26,8 +26,8 @@ func getHealthInfo(r route.Route) map[string]string {
}
type HealthInfoRaw struct {
Status health.Status
Latency time.Duration
Status health.Status `json:"status,string"`
Latency time.Duration `json:"latency"`
}
func getHealthInfoRaw(r route.Route) *HealthInfoRaw {

View file

@ -300,7 +300,3 @@ func (cmd *Command) isBypass() bool {
func (cmd *Command) String() string {
return cmd.raw
}
func (cmd *Command) MarshalText() ([]byte, error) {
return []byte(cmd.String()), nil
}

View file

@ -261,10 +261,6 @@ func (on *RuleOn) String() string {
return on.raw
}
func (on *RuleOn) MarshalText() ([]byte, error) {
return []byte(on.String()), nil
}
func parseOn(line string) (Checker, gperr.Error) {
ors := strutils.SplitRune(line, '|')

View file

@ -1,8 +1,9 @@
package rules
import (
"encoding/json"
"net/http"
"github.com/yusing/go-proxy/pkg/json"
)
type (
@ -40,8 +41,8 @@ type (
*/
Rule struct {
Name string `json:"name"`
On RuleOn `json:"on"`
Do Command `json:"do"`
On RuleOn `json:"on,string"`
Do Command `json:"do,string"`
}
)
@ -102,12 +103,12 @@ func (rules Rules) BuildHandler(caller string, up http.Handler) http.HandlerFunc
}
}
func (rules Rules) MarshalJSON() ([]byte, error) {
func (rules Rules) MarshalJSONTo(buf []byte) []byte {
names := make([]string, len(rules))
for i, rule := range rules {
names[i] = rule.Name
}
return json.Marshal(names)
return json.MarshalTo(names, buf)
}
func (rule *Rule) String() string {

View file

@ -1,8 +1,9 @@
package atomic
import (
"encoding/json"
"sync/atomic"
"github.com/yusing/go-proxy/pkg/json"
)
type Value[T any] struct {
@ -29,6 +30,6 @@ func (a *Value[T]) Swap(v T) T {
return zero
}
func (a *Value[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(a.Load())
func (a *Value[T]) MarshalJSONTo(buf []byte) []byte {
return json.MarshalTo(a.Load(), buf)
}

View file

@ -2,7 +2,6 @@ package utils
import (
"bytes"
"encoding/json"
"errors"
"net"
"net/url"
@ -12,6 +11,8 @@ import (
"strings"
"time"
"github.com/yusing/go-proxy/pkg/json"
"github.com/go-playground/validator/v10"
"github.com/goccy/go-yaml"
"github.com/yusing/go-proxy/internal/gperr"
@ -22,12 +23,15 @@ import (
type SerializedObject = map[string]any
type (
MapMarshaller interface {
MapMarshaler interface {
MarshalMap() map[string]any
}
MapUnmarshaller interface {
UnmarshalMap(m map[string]any) gperr.Error
}
MapUnmarshaler interface {
UnmarshalMap(m map[string]any) gperr.Error
}
Marshaler interface {
MarshalJSONTo(buf *bytes.Buffer) error
}
)
var (
@ -51,11 +55,8 @@ var (
typeURL = reflect.TypeFor[url.URL]()
typeCIDR = reflect.TypeFor[net.IPNet]()
typeMapMarshaller = reflect.TypeFor[MapMarshaller]()
typeMapUnmarshaler = reflect.TypeFor[MapUnmarshaller]()
typeJSONMarshaller = reflect.TypeFor[json.Marshaler]()
typeAny = reflect.TypeOf((*any)(nil)).Elem()
typeMapUnmarshaler = reflect.TypeFor[MapUnmarshaler]()
typeStrParser = reflect.TypeFor[strutils.Parser]()
)
var defaultValues = functional.NewMapOf[reflect.Type, func() any]()
@ -92,14 +93,14 @@ func extractFields(t reflect.Type) (all, anonymous []reflect.StructField) {
if !field.IsExported() {
continue
}
// not checking tagJSON because json:"-" is for skipping json.Marshal
if field.Tag.Get(tagDeserialize) == "-" {
continue
}
if field.Anonymous {
f1, f2 := extractFields(field.Type)
fields = append(fields, f1...)
nested, _ := extractFields(field.Type)
fields = append(fields, nested...)
anonymous = append(anonymous, field)
anonymous = append(anonymous, f2...)
} else {
fields = append(fields, field)
}
@ -215,7 +216,7 @@ func MapUnmarshalValidate(src SerializedObject, dst any) (err gperr.Error) {
if err != nil {
return err
}
return dstV.Addr().Interface().(MapUnmarshaller).UnmarshalMap(src)
return dstV.Addr().Interface().(MapUnmarshaler).UnmarshalMap(src)
}
dstV, dstT, err = dive(dstV)

View file

@ -1,11 +1,12 @@
package monitor
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"github.com/yusing/go-proxy/pkg/json"
agentPkg "github.com/yusing/go-proxy/agent/pkg/agent"
"github.com/yusing/go-proxy/internal/watcher/health"
)

View file

@ -1,6 +1,8 @@
package health
import "encoding/json"
import (
"github.com/yusing/go-proxy/pkg/json"
)
type Status uint8
@ -35,10 +37,6 @@ func (s Status) String() string {
}
}
func (s Status) MarshalJSON() ([]byte, error) {
return []byte(`"` + s.String() + `"`), nil
}
func (s *Status) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {

View file

@ -24,7 +24,7 @@ type (
task.TaskStarter
task.TaskFinisher
fmt.Stringer
utils.MapMarshaller
utils.MapMarshaler
WithHealthInfo
Name() string
}