mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-12 15:09:13 -06:00
Merge pull request #842 from aduffeck/improve-activitylog
Reduce load caused by the activitylog service
This commit is contained in:
@@ -1886,6 +1886,7 @@ def opencloudServer(storage = "decomposed", accounts_hash_difficulty = 4, depend
|
||||
"OC_JWT_SECRET": "some-opencloud-jwt-secret",
|
||||
"EVENTHISTORY_STORE": "memory",
|
||||
"OC_TRANSLATION_PATH": "%s/tests/config/translations" % dirs["base"],
|
||||
"ACTIVITYLOG_WRITE_BUFFER_DURATION": "0", # Disable write buffer so that test expectations are met in time
|
||||
# debug addresses required for running services health tests
|
||||
"ACTIVITYLOG_DEBUG_ADDR": "0.0.0.0:9197",
|
||||
"APP_PROVIDER_DEBUG_ADDR": "0.0.0.0:9165",
|
||||
|
||||
8
go.mod
8
go.mod
@@ -64,7 +64,7 @@ require (
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/open-policy-agent/opa v1.4.2
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5
|
||||
github.com/opencloud-eu/reva/v2 v2.32.0
|
||||
github.com/opencloud-eu/reva/v2 v2.32.1-0.20250515093940-2fb4f836b59d
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/xattr v0.4.10
|
||||
@@ -74,7 +74,6 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.14.1
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/shamaton/msgpack/v2 v2.2.3
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/afero v1.14.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
@@ -85,6 +84,7 @@ require (
|
||||
github.com/tus/tusd/v2 v2.8.0
|
||||
github.com/unrolled/secure v1.16.0
|
||||
github.com/urfave/cli/v2 v2.27.6
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||
go-micro.dev/v4 v4.11.0
|
||||
go.etcd.io/bbolt v1.4.0
|
||||
@@ -99,7 +99,7 @@ require (
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/image v0.27.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/term v0.32.0
|
||||
@@ -291,6 +291,7 @@ require (
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/sethvargo/go-diceware v0.5.0 // indirect
|
||||
github.com/sethvargo/go-password v0.3.1 // indirect
|
||||
github.com/shamaton/msgpack/v2 v2.2.3 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
@@ -303,6 +304,7 @@ require (
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
||||
github.com/trustelem/zxcvbn v1.0.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/wk8/go-ordered-map v1.0.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -862,8 +862,8 @@ github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-202505121527
|
||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5 h1:Wv09oIjCF8zRN8roPzjXXo6ORp2h87/YhmdXE9N4p/A=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.0 h1:JRWPleHiEl0film95Gkh1iBEhc6eikEsx5FKLfVx6l8=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.0/go.mod h1:FDhGVC+ZsRRWdC3am4EbuILBtviTbCDVrTUjFECOqvg=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.1-0.20250515093940-2fb4f836b59d h1:c7AGNgYPm4Ix3YU1vptCN01HjZ1ZpRw91QrqJnSEkxM=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.1-0.20250515093940-2fb4f836b59d/go.mod h1:moFklKM4+TwF8iqeFnX64/8TlbqFSsfAkV30Q0FCTt4=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
@@ -1103,6 +1103,10 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/vultr/govultr/v2 v2.0.0/go.mod h1:2PsEeg+gs3p/Fo5Pw8F9mv+DUBEOlrNZ8GmCTGmhOhs=
|
||||
github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8=
|
||||
github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk=
|
||||
@@ -1322,8 +1326,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// ListBlobstore required to check blob consistency
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -32,6 +32,8 @@ type Config struct {
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
|
||||
Context context.Context `yaml:"-"`
|
||||
|
||||
WriteBufferDuration time.Duration `yaml:"write_buffer_duration" env:"ACTIVITYLOG_WRITE_BUFFER_DURATION" desc:"The duration to wait before flushing the write buffer. This is used to reduce the number of writes to the store." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
|
||||
// Events combines the configuration options for the event bus.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
"github.com/opencloud-eu/opencloud/services/activitylog/pkg/config"
|
||||
@@ -50,6 +52,7 @@ func DefaultConfig() *config.Config {
|
||||
AllowCredentials: true,
|
||||
},
|
||||
},
|
||||
WriteBufferDuration: 10 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.HistoryClient(options.HistoryClient),
|
||||
svc.ValueClient(options.ValueClient),
|
||||
svc.RegisteredEvents(options.RegisteredEvents),
|
||||
svc.WriteBufferDuration(options.Config.WriteBufferDuration),
|
||||
)
|
||||
if err != nil {
|
||||
return http.Service{}, err
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -18,16 +20,17 @@ type Option func(*Options)
|
||||
|
||||
// Options for the activitylog service
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
TraceProvider trace.TracerProvider
|
||||
Stream events.Stream
|
||||
RegisteredEvents []events.Unmarshaller
|
||||
Store microstore.Store
|
||||
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
Mux *chi.Mux
|
||||
HistoryClient ehsvc.EventHistoryService
|
||||
ValueClient settingssvc.ValueService
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
TraceProvider trace.TracerProvider
|
||||
Stream events.Stream
|
||||
RegisteredEvents []events.Unmarshaller
|
||||
Store microstore.Store
|
||||
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
Mux *chi.Mux
|
||||
HistoryClient ehsvc.EventHistoryService
|
||||
ValueClient settingssvc.ValueService
|
||||
WriteBufferDuration time.Duration
|
||||
}
|
||||
|
||||
// Logger configures a logger for the activitylog service
|
||||
@@ -99,3 +102,10 @@ func ValueClient(vs settingssvc.ValueService) Option {
|
||||
o.ValueClient = vs
|
||||
}
|
||||
}
|
||||
|
||||
// WriteBufferDuration sets the write buffer duration
|
||||
func WriteBufferDuration(d time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.WriteBufferDuration = d
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -12,11 +13,14 @@ import (
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
@@ -36,19 +40,92 @@ type RawActivity struct {
|
||||
|
||||
// ActivitylogService logs events per resource
|
||||
type ActivitylogService struct {
|
||||
cfg *config.Config
|
||||
log log.Logger
|
||||
events <-chan events.Event
|
||||
store microstore.Store
|
||||
gws pool.Selectable[gateway.GatewayAPIClient]
|
||||
mux *chi.Mux
|
||||
evHistory ehsvc.EventHistoryService
|
||||
valService settingssvc.ValueService
|
||||
lock sync.RWMutex
|
||||
cfg *config.Config
|
||||
log log.Logger
|
||||
events <-chan events.Event
|
||||
store microstore.Store
|
||||
gws pool.Selectable[gateway.GatewayAPIClient]
|
||||
mux *chi.Mux
|
||||
evHistory ehsvc.EventHistoryService
|
||||
valService settingssvc.ValueService
|
||||
lock sync.RWMutex
|
||||
tp trace.TracerProvider
|
||||
tracer trace.Tracer
|
||||
debouncer *Debouncer
|
||||
parentIdCache *ttlcache.Cache
|
||||
|
||||
registeredEvents map[string]events.Unmarshaller
|
||||
}
|
||||
|
||||
type Debouncer struct {
|
||||
after time.Duration
|
||||
f func(id string, ra []RawActivity) error
|
||||
pending sync.Map
|
||||
inProgress sync.Map
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type queueItem struct {
|
||||
activities []RawActivity
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
// NewDebouncer returns a new Debouncer instance
|
||||
func NewDebouncer(d time.Duration, f func(id string, ra []RawActivity) error) *Debouncer {
|
||||
return &Debouncer{
|
||||
after: d,
|
||||
f: f,
|
||||
pending: sync.Map{},
|
||||
inProgress: sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// Debounce restarts the debounce timer for the given space
|
||||
func (d *Debouncer) Debounce(id string, ra RawActivity) {
|
||||
if d.after == 0 {
|
||||
d.f(id, []RawActivity{ra})
|
||||
return
|
||||
}
|
||||
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
activities := []RawActivity{ra}
|
||||
item := &queueItem{
|
||||
activities: activities,
|
||||
}
|
||||
if i, ok := d.pending.Load(id); ok {
|
||||
// if the item is already in the queue, append the new activities
|
||||
item, ok = i.(*queueItem)
|
||||
if ok {
|
||||
item.activities = append(item.activities, ra)
|
||||
}
|
||||
}
|
||||
|
||||
if item.timer == nil {
|
||||
item.timer = time.AfterFunc(d.after, func() {
|
||||
if _, ok := d.inProgress.Load(id); ok {
|
||||
// Reschedule this run for when the previous run has finished
|
||||
d.mutex.Lock()
|
||||
if i, ok := d.pending.Load(id); ok {
|
||||
i.(*queueItem).timer.Reset(d.after)
|
||||
}
|
||||
|
||||
d.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
d.pending.Delete(id)
|
||||
d.inProgress.Store(id, true)
|
||||
defer d.inProgress.Delete(id)
|
||||
d.f(id, item.activities)
|
||||
})
|
||||
}
|
||||
|
||||
d.pending.Store(id, item)
|
||||
}
|
||||
|
||||
// New creates a new ActivitylogService
|
||||
func New(opts ...Option) (*ActivitylogService, error) {
|
||||
o := &Options{}
|
||||
@@ -69,6 +146,12 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache := ttlcache.NewCache()
|
||||
err = cache.SetTTL(30 * time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &ActivitylogService{
|
||||
log: o.Logger,
|
||||
cfg: o.Config,
|
||||
@@ -80,7 +163,11 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
valService: o.ValueClient,
|
||||
lock: sync.RWMutex{},
|
||||
registeredEvents: make(map[string]events.Unmarshaller),
|
||||
tp: o.TraceProvider,
|
||||
tracer: o.TraceProvider.Tracer("github.com/opencloud-eu/opencloud/services/activitylog/pkg/service"),
|
||||
parentIdCache: cache,
|
||||
}
|
||||
s.debouncer = NewDebouncer(o.WriteBufferDuration, s.storeActivity)
|
||||
|
||||
s.mux.Get("/graph/v1beta1/extensions/org.libregraph/activities", s.HandleGetItemActivities)
|
||||
|
||||
@@ -100,9 +187,9 @@ func (a *ActivitylogService) Run() {
|
||||
var err error
|
||||
switch ev := e.Event.(type) {
|
||||
case events.UploadReady:
|
||||
err = a.AddActivity(ev.FileRef, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.FileRef, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.FileTouched:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.Ref, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
// Disabled https://github.com/owncloud/ocis/issues/10293
|
||||
//case events.FileDownloaded:
|
||||
// we are only interested in public link downloads - so no need to store others.
|
||||
@@ -110,29 +197,32 @@ func (a *ActivitylogService) Run() {
|
||||
// err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
//}
|
||||
case events.ContainerCreated:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.Ref, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ItemTrashed:
|
||||
err = a.AddActivityTrashed(ev.ID, ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivityTrashed(ev.ID, ev.Ref, nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ItemPurged:
|
||||
err = a.RemoveResource(ev.ID)
|
||||
case events.ItemMoved:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
// remove the cached parent id for this resource
|
||||
a.removeCachedParentID(ev.Ref)
|
||||
|
||||
err = a.AddActivity(ev.Ref, nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ShareCreated:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.CTime))
|
||||
case events.ShareUpdated:
|
||||
if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.MTime))
|
||||
}
|
||||
case events.ShareRemoved:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, ev.Timestamp)
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, ev.Timestamp)
|
||||
case events.LinkCreated:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.CTime))
|
||||
case events.LinkUpdated:
|
||||
if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.MTime))
|
||||
}
|
||||
case events.LinkRemoved:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.SpaceShared:
|
||||
err = a.AddSpaceActivity(ev.ID, e.ID, ev.Timestamp)
|
||||
case events.SpaceUnshared:
|
||||
@@ -146,7 +236,7 @@ func (a *ActivitylogService) Run() {
|
||||
}
|
||||
|
||||
// AddActivity adds the activity to the given resource and all its parents
|
||||
func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID string, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) AddActivity(initRef *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time) error {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get gateway client: %w", err)
|
||||
@@ -156,14 +246,17 @@ func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID st
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get service user context: %w", err)
|
||||
}
|
||||
var span trace.Span
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivity")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(initRef, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return a.addActivity(ctx, initRef, parentId, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return utils.GetResource(ctx, ref, gwc)
|
||||
})
|
||||
}
|
||||
|
||||
// AddActivityTrashed adds the activity to given trashed resource and all its former parents
|
||||
func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, reference *provider.Reference, eventID string, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, reference *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time) error {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get gateway client: %w", err)
|
||||
@@ -175,7 +268,13 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId,
|
||||
}
|
||||
|
||||
// store activity on trashed item
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(resourceID), eventID, 0, timestamp); err != nil {
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(resourceID), []RawActivity{
|
||||
{
|
||||
EventID: eventID,
|
||||
Depth: 0,
|
||||
Timestamp: timestamp,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("could not store activity: %w", err)
|
||||
}
|
||||
|
||||
@@ -185,7 +284,11 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId,
|
||||
Path: filepath.Dir(reference.GetPath()),
|
||||
}
|
||||
|
||||
return a.addActivity(ref, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
var span trace.Span
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivity")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(ctx, ref, parentId, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return utils.GetResource(ctx, ref, gwc)
|
||||
})
|
||||
}
|
||||
@@ -200,7 +303,13 @@ func (a *ActivitylogService) AddSpaceActivity(spaceID *provider.StorageSpaceId,
|
||||
return fmt.Errorf("could not parse space id: %w", err)
|
||||
}
|
||||
rid.OpaqueId = rid.GetSpaceId()
|
||||
return a.storeActivity(storagespace.FormatResourceID(&rid), eventID, 0, timestamp)
|
||||
return a.storeActivity(storagespace.FormatResourceID(&rid), []RawActivity{
|
||||
{
|
||||
EventID: eventID,
|
||||
Depth: 0,
|
||||
Timestamp: timestamp,
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -265,70 +374,118 @@ func (a *ActivitylogService) activities(rid *provider.ResourceId) ([]RawActivity
|
||||
}
|
||||
|
||||
var activities []RawActivity
|
||||
if err := json.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal activities: %w", err)
|
||||
if err := msgpack.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
if err := json.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal activities: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return activities, nil
|
||||
}
|
||||
|
||||
// note: getResource is abstracted to allow unit testing, in general this will just be utils.GetResource
|
||||
func (a *ActivitylogService) addActivity(initRef *provider.Reference, eventID string, timestamp time.Time, getResource func(*provider.Reference) (*provider.ResourceInfo, error)) error {
|
||||
func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time, getResource func(*provider.Reference) (*provider.ResourceInfo, error)) error {
|
||||
var (
|
||||
info *provider.ResourceInfo
|
||||
err error
|
||||
depth int
|
||||
ref = initRef
|
||||
)
|
||||
for {
|
||||
info, err = getResource(ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get resource info: %w", err)
|
||||
var info *provider.ResourceInfo
|
||||
id := ref.GetResourceId()
|
||||
if ref.Path != "" {
|
||||
// Path based reference, we need to resolve the resource id
|
||||
info, err = getResource(ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get resource info: %w", err)
|
||||
}
|
||||
id = info.GetId()
|
||||
}
|
||||
if id == nil {
|
||||
return fmt.Errorf("resource id is required")
|
||||
}
|
||||
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(info.GetId()), eventID, depth, timestamp); err != nil {
|
||||
return fmt.Errorf("could not store activity: %w", err)
|
||||
}
|
||||
key := storagespace.FormatResourceID(id)
|
||||
_, span := a.tracer.Start(ctx, "queueStoreActivity")
|
||||
a.debouncer.Debounce(key, RawActivity{
|
||||
EventID: eventID,
|
||||
Depth: depth,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
span.End()
|
||||
|
||||
if info != nil && utils.IsSpaceRoot(info) {
|
||||
if id.OpaqueId == id.SpaceId {
|
||||
// we are at the root of the space, no need to go further
|
||||
return nil
|
||||
}
|
||||
|
||||
// check if parent id is cached
|
||||
// parent id is cached in the format <storageid>$<spaceid>!<resourceid>
|
||||
// if it is not cached, get the resource info and cache it
|
||||
if parentId == nil {
|
||||
if v, err := a.parentIdCache.Get(key); err != nil {
|
||||
if info == nil {
|
||||
_, span = a.tracer.Start(ctx, "getResource")
|
||||
info, err = getResource(ref)
|
||||
span.End()
|
||||
if err != nil || info.GetParentId() == nil || info.GetParentId().GetOpaqueId() == "" {
|
||||
return fmt.Errorf("could not get parent id: %w", err)
|
||||
}
|
||||
}
|
||||
parentId = info.GetParentId()
|
||||
a.parentIdCache.Set(key, parentId)
|
||||
} else {
|
||||
parentId = v.(*provider.ResourceId)
|
||||
}
|
||||
} else {
|
||||
a.log.Debug().Msg("parent id is cached")
|
||||
}
|
||||
|
||||
depth++
|
||||
ref = &provider.Reference{ResourceId: info.GetParentId()}
|
||||
ref = &provider.Reference{ResourceId: parentId}
|
||||
parentId = nil // reset parent id so it's not reused in the next iteration
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) storeActivity(resourceID string, eventID string, depth int, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) storeActivity(resourceID string, activities []RawActivity) error {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
ctx, span := a.tracer.Start(context.Background(), "storeActivity")
|
||||
defer span.End()
|
||||
_, subspan := a.tracer.Start(ctx, "store.Read")
|
||||
records, err := a.store.Read(resourceID)
|
||||
if err != nil && err != microstore.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
var activities []RawActivity
|
||||
_, subspan = a.tracer.Start(ctx, "Unmarshal")
|
||||
var existingActivities []RawActivity
|
||||
if len(records) > 0 {
|
||||
if err := json.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
return err
|
||||
if err := msgpack.Unmarshal(records[0].Value, &existingActivities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
if err := json.Unmarshal(records[0].Value, &existingActivities); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
if l := len(activities); l >= _maxActivities {
|
||||
activities = activities[l-_maxActivities+1:]
|
||||
if l := len(existingActivities) + len(activities); l >= _maxActivities {
|
||||
start := min(len(existingActivities), l-_maxActivities+1)
|
||||
existingActivities = existingActivities[start:]
|
||||
}
|
||||
|
||||
activities = append(activities, RawActivity{
|
||||
EventID: eventID,
|
||||
Depth: depth,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
activities = append(existingActivities, activities...)
|
||||
|
||||
b, err := json.Marshal(activities)
|
||||
_, subspan = a.tracer.Start(ctx, "Unmarshal")
|
||||
b, err := msgpack.Marshal(activities)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
return a.store.Write(µstore.Record{
|
||||
Key: resourceID,
|
||||
@@ -347,3 +504,30 @@ func toSpace(r *provider.Reference) *provider.StorageSpaceId {
|
||||
OpaqueId: storagespace.FormatStorageID(r.GetResourceId().GetStorageId(), r.GetResourceId().GetSpaceId()),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) removeCachedParentID(ref *provider.Reference) {
|
||||
purgeId := ref.GetResourceId()
|
||||
if ref.GetPath() != "" {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get gateway client")
|
||||
return
|
||||
}
|
||||
|
||||
ctx, err := utils.GetServiceUserContext(a.cfg.ServiceAccount.ServiceAccountID, gwc, a.cfg.ServiceAccount.ServiceAccountSecret)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get service user context")
|
||||
return
|
||||
}
|
||||
|
||||
info, err := utils.GetResource(ctx, ref, gwc)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get resource info")
|
||||
return
|
||||
}
|
||||
purgeId = info.GetId()
|
||||
}
|
||||
if err := a.parentIdCache.Remove(storagespace.FormatResourceID(purgeId)); err != nil {
|
||||
a.log.Error().Interface("event", ref).Err(err).Msg("could not delete parent id cache")
|
||||
}
|
||||
}
|
||||
|
||||
13
services/activitylog/pkg/service/service_suite_test.go
Normal file
13
services/activitylog/pkg/service/service_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package service_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Service Suite")
|
||||
}
|
||||
@@ -1,147 +1,139 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
func TestAddActivity(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Tree map[string]*provider.ResourceInfo
|
||||
Activities map[string]string
|
||||
Expected map[string][]RawActivity
|
||||
}{
|
||||
{
|
||||
Name: "simple",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
var _ = Describe("ActivitylogService", func() {
|
||||
var (
|
||||
alog *ActivitylogService
|
||||
getResource func(ref *provider.Reference) (*provider.ResourceInfo, error)
|
||||
)
|
||||
|
||||
Context("with a noop debouncer", func() {
|
||||
BeforeEach(func() {
|
||||
alog = &ActivitylogService{
|
||||
store: store.Create(),
|
||||
tracer: noop.NewTracerProvider().Tracer("test"),
|
||||
parentIdCache: ttlcache.NewCache(),
|
||||
}
|
||||
alog.debouncer = NewDebouncer(0, alog.storeActivity)
|
||||
})
|
||||
|
||||
Describe("AddActivity", func() {
|
||||
type testCase struct {
|
||||
Name string
|
||||
Tree map[string]*provider.ResourceInfo
|
||||
Activities map[string]string
|
||||
Expected map[string][]RawActivity
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
Name: "simple",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity", 0),
|
||||
"parent": activitites("activity", 1),
|
||||
"spaceid": activitites("activity", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on same resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base",
|
||||
"activity2": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity1", 0, "activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
// Add other test cases here...
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc // capture range variable
|
||||
Context(tc.Name, func() {
|
||||
BeforeEach(func() {
|
||||
getResource = func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tc.Tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
for k, v := range tc.Activities {
|
||||
err := alog.addActivity(context.Background(), reference(v), nil, k, time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
})
|
||||
|
||||
It("should match the expected activities", func() {
|
||||
for id, acts := range tc.Expected {
|
||||
activities, err := alog.Activities(resourceID(id))
|
||||
Expect(err).NotTo(HaveOccurred(), tc.Name+":"+id)
|
||||
Expect(activities).To(ConsistOf(acts), tc.Name+":"+id)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Context("with a debouncing debouncer", func() {
|
||||
var (
|
||||
tree = map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity", 0),
|
||||
"parent": activitites("activity", 1),
|
||||
"spaceid": activitites("activity", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on same resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base",
|
||||
"activity2": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity1", 0, "activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on different resources",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent"),
|
||||
"base2": resourceInfo("base2", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "more elaborate resource tree",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent1"),
|
||||
"base2": resourceInfo("base2", "parent1"),
|
||||
"parent1": resourceInfo("parent1", "spaceid"),
|
||||
"base3": resourceInfo("base3", "parent2"),
|
||||
"parent2": resourceInfo("parent2", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
"activity3": "base3",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"base3": activitites("activity3", 0),
|
||||
"parent1": activitites("activity1", 1, "activity2", 1),
|
||||
"parent2": activitites("activity3", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2, "activity3", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "different depths within one resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent1"),
|
||||
"parent1": resourceInfo("parent1", "parent2"),
|
||||
"base2": resourceInfo("base2", "parent2"),
|
||||
"parent2": resourceInfo("parent2", "parent3"),
|
||||
"base3": resourceInfo("base3", "parent3"),
|
||||
"parent3": resourceInfo("parent3", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
"activity3": "base3",
|
||||
"activity4": "parent2",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"base3": activitites("activity3", 0),
|
||||
"parent1": activitites("activity1", 1),
|
||||
"parent2": activitites("activity1", 2, "activity2", 1, "activity4", 0),
|
||||
"parent3": activitites("activity1", 3, "activity2", 2, "activity3", 1, "activity4", 1),
|
||||
"spaceid": activitites("activity1", 4, "activity2", 3, "activity3", 2, "activity4", 2),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
BeforeEach(func() {
|
||||
alog = &ActivitylogService{
|
||||
store: store.Create(),
|
||||
tracer: noop.NewTracerProvider().Tracer("test"),
|
||||
parentIdCache: ttlcache.NewCache(),
|
||||
}
|
||||
alog.debouncer = NewDebouncer(100*time.Millisecond, alog.storeActivity)
|
||||
})
|
||||
|
||||
for _, tc := range testCases {
|
||||
alog := &ActivitylogService{
|
||||
store: store.Create(),
|
||||
}
|
||||
It("should debounce activities", func() {
|
||||
getResource = func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
getResource := func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tc.Tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
err := alog.addActivity(context.Background(), reference("base"), nil, "activity1", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity2", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
for k, v := range tc.Activities {
|
||||
err := alog.addActivity(reference(v), k, time.Time{}, getResource)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for id, acts := range tc.Expected {
|
||||
activities, err := alog.Activities(resourceID(id))
|
||||
require.NoError(t, err, tc.Name+":"+id)
|
||||
require.ElementsMatch(t, acts, activities, tc.Name+":"+id)
|
||||
}
|
||||
}
|
||||
}
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity1", 0, "activity2", 0)))
|
||||
}).Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func activitites(acts ...interface{}) []RawActivity {
|
||||
var activities []RawActivity
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/oidc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
store "go-micro.dev/v4/store"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -66,7 +66,7 @@ func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[stri
|
||||
m.Logger.Error().Err(err).Msg("could not read from userinfo cache")
|
||||
}
|
||||
if len(record) > 0 {
|
||||
if err = msgpack.UnmarshalAsMap(record[0].Value, &claims); err == nil {
|
||||
if err = msgpack.Unmarshal(record[0].Value, &claims); err == nil {
|
||||
m.Logger.Debug().Interface("claims", claims).Msg("cache hit for userinfo")
|
||||
if ok := verifyExpiresAt(claims, m.TimeFunc()); !ok {
|
||||
return nil, false, jwt.ErrTokenExpired
|
||||
@@ -102,7 +102,7 @@ func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[stri
|
||||
// always set an exp claim
|
||||
claims["exp"] = expiration.Unix()
|
||||
go func() {
|
||||
if d, err := msgpack.MarshalAsMap(claims); err != nil {
|
||||
if d, err := msgpack.Marshal(claims); err != nil {
|
||||
m.Logger.Error().Err(err).Msg("failed to marshal claims for userinfo cache")
|
||||
} else {
|
||||
err = m.userInfoCache.Write(&store.Record{
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ func (s StaticRouteHandler) publishBackchannelLogoutEvent(ctx context.Context, r
|
||||
}
|
||||
|
||||
var claims map[string]interface{}
|
||||
if err = msgpack.UnmarshalAsMap(urecords[0].Value, &claims); err != nil {
|
||||
if err = msgpack.Unmarshal(urecords[0].Value, &claims); err != nil {
|
||||
return fmt.Errorf("could not unmarshal userinfo: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
olog "github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/config"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/events/files.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/events/files.go
generated
vendored
@@ -31,6 +31,7 @@ type ContainerCreated struct {
|
||||
SpaceOwner *user.UserId
|
||||
Executant *user.UserId
|
||||
Ref *provider.Reference
|
||||
ParentID *provider.ResourceId
|
||||
Owner *user.UserId
|
||||
Timestamp *types.Timestamp
|
||||
ImpersonatingUser *user.User
|
||||
@@ -65,6 +66,7 @@ type FileTouched struct {
|
||||
SpaceOwner *user.UserId
|
||||
Executant *user.UserId
|
||||
Ref *provider.Reference
|
||||
ParentID *provider.ResourceId
|
||||
Timestamp *types.Timestamp
|
||||
ImpersonatingUser *user.User
|
||||
}
|
||||
|
||||
1
vendor/github.com/opencloud-eu/reva/v2/pkg/events/postprocessing.go
generated
vendored
1
vendor/github.com/opencloud-eu/reva/v2/pkg/events/postprocessing.go
generated
vendored
@@ -184,6 +184,7 @@ type UploadReady struct {
|
||||
ExecutingUser *user.User
|
||||
ImpersonatingUser *user.User
|
||||
FileRef *provider.Reference
|
||||
ParentID *provider.ResourceId
|
||||
Timestamp *types.Timestamp
|
||||
Failed bool
|
||||
IsVersion bool
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/cache/cache.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/cache/cache.go
generated
vendored
@@ -28,7 +28,7 @@ import (
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
|
||||
14
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go
generated
vendored
14
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go
generated
vendored
@@ -521,11 +521,20 @@ func (t *Tree) assimilate(item scanItem) error {
|
||||
|
||||
// assimilate new file
|
||||
newId := uuid.New().String()
|
||||
fi, _, err := t.updateFile(item.Path, newId, spaceID, nil)
|
||||
fi, attrs, err := t.updateFile(item.Path, newId, spaceID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var parentId *provider.ResourceId
|
||||
if len(attrs[prefixes.ParentidAttr]) > 0 {
|
||||
parentId = &provider.ResourceId{
|
||||
StorageId: t.options.MountID,
|
||||
SpaceId: spaceID,
|
||||
OpaqueId: string(attrs[prefixes.ParentidAttr]),
|
||||
}
|
||||
}
|
||||
|
||||
ref := &provider.Reference{
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: t.options.MountID,
|
||||
@@ -536,17 +545,20 @@ func (t *Tree) assimilate(item scanItem) error {
|
||||
if fi.IsDir() {
|
||||
t.PublishEvent(events.ContainerCreated{
|
||||
Ref: ref,
|
||||
ParentID: parentId,
|
||||
Timestamp: utils.TSNow(),
|
||||
})
|
||||
} else {
|
||||
if fi.Size() == 0 {
|
||||
t.PublishEvent(events.FileTouched{
|
||||
Ref: ref,
|
||||
ParentID: parentId,
|
||||
Timestamp: utils.TSNow(),
|
||||
})
|
||||
} else {
|
||||
t.PublishEvent(events.UploadReady{
|
||||
FileRef: ref,
|
||||
ParentID: parentId,
|
||||
Timestamp: utils.TSNow(),
|
||||
})
|
||||
}
|
||||
|
||||
3
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go
generated
vendored
3
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go
generated
vendored
@@ -453,7 +453,8 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
|
||||
|
||||
child, err := node.ReadNode(ctx, t.lookup, n.SpaceID, nodeID, false, n.SpaceRoot, true)
|
||||
if err != nil {
|
||||
return err
|
||||
t.log.Error().Err(err).Str("path", path).Msg("failed to read node")
|
||||
continue
|
||||
}
|
||||
|
||||
// prevent listing denied resources
|
||||
|
||||
7
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go
generated
vendored
7
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go
generated
vendored
@@ -343,6 +343,7 @@ func (fs *Decomposedfs) Postprocessing(ch <-chan events.Event) {
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var parentId *provider.ResourceId
|
||||
if failed {
|
||||
// if no other upload session is in progress (processing id != session id) or has finished (processing id == "")
|
||||
latestSession, err := n.ProcessingID(ctx)
|
||||
@@ -356,6 +357,11 @@ func (fs *Decomposedfs) Postprocessing(ch <-chan events.Event) {
|
||||
}
|
||||
}
|
||||
} else if p := getParent(); p != nil {
|
||||
parentId = &provider.ResourceId{
|
||||
StorageId: session.ProviderID(),
|
||||
SpaceId: session.SpaceID(),
|
||||
OpaqueId: p.ID,
|
||||
}
|
||||
// update parent tmtime to propagate etag change after successful postprocessing
|
||||
_ = p.SetTMTime(ctx, &now)
|
||||
if err := fs.tp.Propagate(ctx, p, 0); err != nil {
|
||||
@@ -389,6 +395,7 @@ func (fs *Decomposedfs) Postprocessing(ch <-chan events.Event) {
|
||||
},
|
||||
Path: utils.MakeRelativePath(filepath.Join(session.Dir(), session.Filename())),
|
||||
},
|
||||
ParentID: parentId,
|
||||
Timestamp: utils.TimeToTS(now),
|
||||
SpaceOwner: n.SpaceOwnerOrManager(ctx),
|
||||
IsVersion: isVersion,
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/pkg/xattr"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/cache"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
"github.com/pkg/xattr"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/mtimesyncedcache"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// Index holds space id indexes
|
||||
|
||||
8
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go
generated
vendored
8
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go
generated
vendored
@@ -52,7 +52,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -129,7 +129,11 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr
|
||||
}
|
||||
|
||||
// 770 permissions for the space
|
||||
if err := os.MkdirAll(rootPath, 0770); err != nil {
|
||||
if err := os.Mkdir(rootPath, 0770); err != nil {
|
||||
if os.IsExist(err) {
|
||||
// Someone has created the space in the meantime. Abort.
|
||||
return nil, errtypes.AlreadyExists(spaceID)
|
||||
}
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("Decomposedfs: error creating space %s", rootPath))
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/options"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
var _propagationGracePeriod = 3 * time.Minute
|
||||
|
||||
4
vendor/github.com/vmihailenco/msgpack/v5/.prettierrc
generated
vendored
Normal file
4
vendor/github.com/vmihailenco/msgpack/v5/.prettierrc
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
semi: false
|
||||
singleQuote: true
|
||||
proseWrap: always
|
||||
printWidth: 100
|
||||
20
vendor/github.com/vmihailenco/msgpack/v5/.travis.yml
generated
vendored
Normal file
20
vendor/github.com/vmihailenco/msgpack/v5/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
go_import_path: github.com/vmihailenco/msgpack
|
||||
|
||||
before_install:
|
||||
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go
|
||||
env GOPATH)/bin v1.31.0
|
||||
75
vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md
generated
vendored
Normal file
75
vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
## [5.4.1](https://github.com/vmihailenco/msgpack/compare/v5.4.0...v5.4.1) (2023-10-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reflect:** not assignable to type ([edeaedd](https://github.com/vmihailenco/msgpack/commit/edeaeddb2d51868df8c6ff2d8a218b527aeaf5fd))
|
||||
|
||||
|
||||
|
||||
# [5.4.0](https://github.com/vmihailenco/msgpack/compare/v5.3.6...v5.4.0) (2023-10-01)
|
||||
|
||||
|
||||
|
||||
## [5.3.6](https://github.com/vmihailenco/msgpack/compare/v5.3.5...v5.3.6) (2023-10-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow overwriting time.Time parsing from extID 13 (for NodeJS Date) ([9a6b73b](https://github.com/vmihailenco/msgpack/commit/9a6b73b3588fd962d568715f4375e24b089f7066))
|
||||
* apply omitEmptyFlag to empty structs ([e5f8d03](https://github.com/vmihailenco/msgpack/commit/e5f8d03c0a1dd9cc571d648cd610305139078de5))
|
||||
* support sorted keys for map[string]bool ([690c1fa](https://github.com/vmihailenco/msgpack/commit/690c1fab9814fab4842295ea986111f49850d9a4))
|
||||
|
||||
|
||||
|
||||
## [5.3.5](https://github.com/vmihailenco/msgpack/compare/v5.3.4...v5.3.5) (2021-10-22)
|
||||
|
||||
- Allow decoding `nil` code as boolean false.
|
||||
|
||||
## v5
|
||||
|
||||
### Added
|
||||
|
||||
- `DecodeMap` is split into `DecodeMap`, `DecodeTypedMap`, and `DecodeUntypedMap`.
|
||||
- New msgpack extensions API.
|
||||
|
||||
### Changed
|
||||
|
||||
- `Reset*` functions also reset flags.
|
||||
- `SetMapDecodeFunc` is renamed to `SetMapDecoder`.
|
||||
- `StructAsArray` is renamed to `UseArrayEncodedStructs`.
|
||||
- `SortMapKeys` is renamed to `SetSortMapKeys`.
|
||||
|
||||
### Removed
|
||||
|
||||
- `UseJSONTag` is removed. Use `SetCustomStructTag("json")` instead.
|
||||
|
||||
## v4
|
||||
|
||||
- Encode, Decode, Marshal, and Unmarshal are changed to accept single argument. EncodeMulti and
|
||||
DecodeMulti are added as replacement.
|
||||
- Added EncodeInt8/16/32/64 and EncodeUint8/16/32/64.
|
||||
- Encoder changed to preserve type of numbers instead of chosing most compact encoding. The old
|
||||
behavior can be achieved with Encoder.UseCompactEncoding.
|
||||
|
||||
## v3.3
|
||||
|
||||
- `msgpack:",inline"` tag is restored to force inlining structs.
|
||||
|
||||
## v3.2
|
||||
|
||||
- Decoding extension types returns pointer to the value instead of the value. Fixes #153
|
||||
|
||||
## v3
|
||||
|
||||
- gopkg.in is not supported any more. Update import path to github.com/vmihailenco/msgpack.
|
||||
- Msgpack maps are decoded into map[string]interface{} by default.
|
||||
- EncodeSliceLen is removed in favor of EncodeArrayLen. DecodeSliceLen is removed in favor of
|
||||
DecodeArrayLen.
|
||||
- Embedded structs are automatically inlined where possible.
|
||||
- Time is encoded using extension as described in https://github.com/msgpack/msgpack/pull/209. Old
|
||||
format is supported as well.
|
||||
- EncodeInt8/16/32/64 is replaced with EncodeInt. EncodeUint8/16/32/64 is replaced with EncodeUint.
|
||||
There should be no performance differences.
|
||||
- DecodeInterface can now return int8/16/32 and uint8/16/32.
|
||||
- PeekCode returns codes.Code instead of byte.
|
||||
25
vendor/github.com/vmihailenco/msgpack/v5/LICENSE
generated
vendored
Normal file
25
vendor/github.com/vmihailenco/msgpack/v5/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
6
vendor/github.com/vmihailenco/msgpack/v5/Makefile
generated
vendored
Normal file
6
vendor/github.com/vmihailenco/msgpack/v5/Makefile
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
test:
|
||||
go test ./...
|
||||
go test ./... -short -race
|
||||
go test ./... -run=NONE -bench=. -benchmem
|
||||
env GOOS=linux GOARCH=386 go test ./...
|
||||
go vet
|
||||
100
vendor/github.com/vmihailenco/msgpack/v5/README.md
generated
vendored
Normal file
100
vendor/github.com/vmihailenco/msgpack/v5/README.md
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
# MessagePack encoding for Golang
|
||||
|
||||
[](https://travis-ci.org/vmihailenco/msgpack)
|
||||
[](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5)
|
||||
[](https://msgpack.uptrace.dev/)
|
||||
[](https://discord.gg/rWtp5Aj)
|
||||
|
||||
> msgpack is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace).
|
||||
> Uptrace is an [open source APM](https://uptrace.dev/get/open-source-apm.html) and blazingly fast
|
||||
> [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered
|
||||
> by OpenTelemetry and ClickHouse. Give it a star as well!
|
||||
|
||||
## Resources
|
||||
|
||||
- [Documentation](https://msgpack.uptrace.dev)
|
||||
- [Chat](https://discord.gg/rWtp5Aj)
|
||||
- [Reference](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5)
|
||||
- [Examples](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#pkg-examples)
|
||||
|
||||
## Features
|
||||
|
||||
- Primitives, arrays, maps, structs, time.Time and interface{}.
|
||||
- Appengine \*datastore.Key and datastore.Cursor.
|
||||
- [CustomEncoder]/[CustomDecoder] interfaces for custom encoding.
|
||||
- [Extensions](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-RegisterExt) to encode
|
||||
type information.
|
||||
- Renaming fields via `msgpack:"my_field_name"` and alias via `msgpack:"alias:another_name"`.
|
||||
- Omitting individual empty fields via `msgpack:",omitempty"` tag or all
|
||||
[empty fields in a struct](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-OmitEmpty).
|
||||
- [Map keys sorting](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetSortMapKeys).
|
||||
- Encoding/decoding all
|
||||
[structs as arrays](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.UseArrayEncodedStructs)
|
||||
or
|
||||
[individual structs](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-AsArray).
|
||||
- [Encoder.SetCustomStructTag] with [Decoder.SetCustomStructTag] can turn msgpack into drop-in
|
||||
replacement for any tag.
|
||||
- Simple but very fast and efficient
|
||||
[queries](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Decoder.Query).
|
||||
|
||||
[customencoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomEncoder
|
||||
[customdecoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomDecoder
|
||||
[encoder.setcustomstructtag]:
|
||||
https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetCustomStructTag
|
||||
[decoder.setcustomstructtag]:
|
||||
https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Decoder.SetCustomStructTag
|
||||
|
||||
## Installation
|
||||
|
||||
msgpack supports 2 last Go versions and requires support for
|
||||
[Go modules](https://github.com/golang/go/wiki/Modules). So make sure to initialize a Go module:
|
||||
|
||||
```shell
|
||||
go mod init github.com/my/repo
|
||||
```
|
||||
|
||||
And then install msgpack/v5 (note _v5_ in the import; omitting it is a popular mistake):
|
||||
|
||||
```shell
|
||||
go get github.com/vmihailenco/msgpack/v5
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
```go
|
||||
import "github.com/vmihailenco/msgpack/v5"
|
||||
|
||||
func ExampleMarshal() {
|
||||
type Item struct {
|
||||
Foo string
|
||||
}
|
||||
|
||||
b, err := msgpack.Marshal(&Item{Foo: "bar"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var item Item
|
||||
err = msgpack.Unmarshal(b, &item)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(item.Foo)
|
||||
// Output: bar
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Golang ORM](https://github.com/uptrace/bun) for PostgreSQL, MySQL, MSSQL, and SQLite
|
||||
- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/)
|
||||
- [Golang HTTP router](https://github.com/uptrace/bunrouter)
|
||||
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks to all the people who already contributed!
|
||||
|
||||
<a href="https://github.com/vmihailenco/msgpack/graphs/contributors">
|
||||
<img src="https://contributors-img.web.app/image?repo=vmihailenco/msgpack" />
|
||||
</a>
|
||||
1
vendor/github.com/vmihailenco/msgpack/v5/commitlint.config.js
generated
vendored
Normal file
1
vendor/github.com/vmihailenco/msgpack/v5/commitlint.config.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: ['@commitlint/config-conventional'] }
|
||||
708
vendor/github.com/vmihailenco/msgpack/v5/decode.go
generated
vendored
Normal file
708
vendor/github.com/vmihailenco/msgpack/v5/decode.go
generated
vendored
Normal file
@@ -0,0 +1,708 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
const (
|
||||
bytesAllocLimit = 1 << 20 // 1mb
|
||||
sliceAllocLimit = 1e6 // 1m elements
|
||||
maxMapSize = 1e6 // 1m elements
|
||||
)
|
||||
|
||||
const (
|
||||
looseInterfaceDecodingFlag uint32 = 1 << iota
|
||||
disallowUnknownFieldsFlag
|
||||
usePreallocateValues
|
||||
disableAllocLimitFlag
|
||||
)
|
||||
|
||||
type bufReader interface {
|
||||
io.Reader
|
||||
io.ByteScanner
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var decPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return NewDecoder(nil)
|
||||
},
|
||||
}
|
||||
|
||||
func GetDecoder() *Decoder {
|
||||
return decPool.Get().(*Decoder)
|
||||
}
|
||||
|
||||
func PutDecoder(dec *Decoder) {
|
||||
dec.r = nil
|
||||
dec.s = nil
|
||||
decPool.Put(dec)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Unmarshal decodes the MessagePack-encoded data and stores the result
|
||||
// in the value pointed to by v.
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
dec := GetDecoder()
|
||||
dec.UsePreallocateValues(true)
|
||||
dec.Reset(bytes.NewReader(data))
|
||||
err := dec.Decode(v)
|
||||
|
||||
PutDecoder(dec)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// A Decoder reads and decodes MessagePack values from an input stream.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
s io.ByteScanner
|
||||
mapDecoder func(*Decoder) (interface{}, error)
|
||||
structTag string
|
||||
buf []byte
|
||||
rec []byte
|
||||
dict []string
|
||||
flags uint32
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
//
|
||||
// The decoder introduces its own buffering and may read data from r
|
||||
// beyond the requested msgpack values. Buffering can be disabled
|
||||
// by passing a reader that implements io.ByteScanner interface.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
d := new(Decoder)
|
||||
d.Reset(r)
|
||||
return d
|
||||
}
|
||||
|
||||
// Reset discards any buffered data, resets all state, and switches the buffered
|
||||
// reader to read from r.
|
||||
func (d *Decoder) Reset(r io.Reader) {
|
||||
d.ResetDict(r, nil)
|
||||
}
|
||||
|
||||
// ResetDict is like Reset, but also resets the dict.
|
||||
func (d *Decoder) ResetDict(r io.Reader, dict []string) {
|
||||
d.ResetReader(r)
|
||||
d.flags = 0
|
||||
d.structTag = ""
|
||||
d.dict = dict
|
||||
}
|
||||
|
||||
func (d *Decoder) WithDict(dict []string, fn func(*Decoder) error) error {
|
||||
oldDict := d.dict
|
||||
d.dict = dict
|
||||
err := fn(d)
|
||||
d.dict = oldDict
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) ResetReader(r io.Reader) {
|
||||
d.mapDecoder = nil
|
||||
d.dict = nil
|
||||
|
||||
if br, ok := r.(bufReader); ok {
|
||||
d.r = br
|
||||
d.s = br
|
||||
} else if r == nil {
|
||||
d.r = nil
|
||||
d.s = nil
|
||||
} else {
|
||||
br := bufio.NewReader(r)
|
||||
d.r = br
|
||||
d.s = br
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) SetMapDecoder(fn func(*Decoder) (interface{}, error)) {
|
||||
d.mapDecoder = fn
|
||||
}
|
||||
|
||||
// UseLooseInterfaceDecoding causes decoder to use DecodeInterfaceLoose
|
||||
// to decode msgpack value into Go interface{}.
|
||||
func (d *Decoder) UseLooseInterfaceDecoding(on bool) {
|
||||
if on {
|
||||
d.flags |= looseInterfaceDecodingFlag
|
||||
} else {
|
||||
d.flags &= ^looseInterfaceDecodingFlag
|
||||
}
|
||||
}
|
||||
|
||||
// SetCustomStructTag causes the decoder to use the supplied tag as a fallback option
|
||||
// if there is no msgpack tag.
|
||||
func (d *Decoder) SetCustomStructTag(tag string) {
|
||||
d.structTag = tag
|
||||
}
|
||||
|
||||
// DisallowUnknownFields causes the Decoder to return an error when the destination
|
||||
// is a struct and the input contains object keys which do not match any
|
||||
// non-ignored, exported fields in the destination.
|
||||
func (d *Decoder) DisallowUnknownFields(on bool) {
|
||||
if on {
|
||||
d.flags |= disallowUnknownFieldsFlag
|
||||
} else {
|
||||
d.flags &= ^disallowUnknownFieldsFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UseInternedStrings enables support for decoding interned strings.
|
||||
func (d *Decoder) UseInternedStrings(on bool) {
|
||||
if on {
|
||||
d.flags |= useInternedStringsFlag
|
||||
} else {
|
||||
d.flags &= ^useInternedStringsFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UsePreallocateValues enables preallocating values in chunks
|
||||
func (d *Decoder) UsePreallocateValues(on bool) {
|
||||
if on {
|
||||
d.flags |= usePreallocateValues
|
||||
} else {
|
||||
d.flags &= ^usePreallocateValues
|
||||
}
|
||||
}
|
||||
|
||||
// DisableAllocLimit enables fully allocating slices/maps when the size is known
|
||||
func (d *Decoder) DisableAllocLimit(on bool) {
|
||||
if on {
|
||||
d.flags |= disableAllocLimitFlag
|
||||
} else {
|
||||
d.flags &= ^disableAllocLimitFlag
|
||||
}
|
||||
}
|
||||
|
||||
// Buffered returns a reader of the data remaining in the Decoder's buffer.
|
||||
// The reader is valid until the next call to Decode.
|
||||
func (d *Decoder) Buffered() io.Reader {
|
||||
return d.r
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (d *Decoder) Decode(v interface{}) error {
|
||||
var err error
|
||||
switch v := v.(type) {
|
||||
case *string:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeString()
|
||||
return err
|
||||
}
|
||||
case *[]byte:
|
||||
if v != nil {
|
||||
return d.decodeBytesPtr(v)
|
||||
}
|
||||
case *int:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeInt()
|
||||
return err
|
||||
}
|
||||
case *int8:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeInt8()
|
||||
return err
|
||||
}
|
||||
case *int16:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeInt16()
|
||||
return err
|
||||
}
|
||||
case *int32:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeInt32()
|
||||
return err
|
||||
}
|
||||
case *int64:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeInt64()
|
||||
return err
|
||||
}
|
||||
case *uint:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeUint()
|
||||
return err
|
||||
}
|
||||
case *uint8:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeUint8()
|
||||
return err
|
||||
}
|
||||
case *uint16:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeUint16()
|
||||
return err
|
||||
}
|
||||
case *uint32:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeUint32()
|
||||
return err
|
||||
}
|
||||
case *uint64:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeUint64()
|
||||
return err
|
||||
}
|
||||
case *bool:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeBool()
|
||||
return err
|
||||
}
|
||||
case *float32:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeFloat32()
|
||||
return err
|
||||
}
|
||||
case *float64:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeFloat64()
|
||||
return err
|
||||
}
|
||||
case *[]string:
|
||||
return d.decodeStringSlicePtr(v)
|
||||
case *map[string]string:
|
||||
return d.decodeMapStringStringPtr(v)
|
||||
case *map[string]interface{}:
|
||||
return d.decodeMapStringInterfacePtr(v)
|
||||
case *time.Duration:
|
||||
if v != nil {
|
||||
vv, err := d.DecodeInt64()
|
||||
*v = time.Duration(vv)
|
||||
return err
|
||||
}
|
||||
case *time.Time:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeTime()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
vv := reflect.ValueOf(v)
|
||||
if !vv.IsValid() {
|
||||
return errors.New("msgpack: Decode(nil)")
|
||||
}
|
||||
if vv.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("msgpack: Decode(non-pointer %T)", v)
|
||||
}
|
||||
if vv.IsNil() {
|
||||
return fmt.Errorf("msgpack: Decode(non-settable %T)", v)
|
||||
}
|
||||
|
||||
vv = vv.Elem()
|
||||
if vv.Kind() == reflect.Interface {
|
||||
if !vv.IsNil() {
|
||||
vv = vv.Elem()
|
||||
if vv.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("msgpack: Decode(non-pointer %s)", vv.Type().String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return d.DecodeValue(vv)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeMulti(v ...interface{}) error {
|
||||
for _, vv := range v {
|
||||
if err := d.Decode(vv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInterfaceCond() (interface{}, error) {
|
||||
if d.flags&looseInterfaceDecodingFlag != 0 {
|
||||
return d.DecodeInterfaceLoose()
|
||||
}
|
||||
return d.DecodeInterface()
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeValue(v reflect.Value) error {
|
||||
decode := getDecoder(v.Type())
|
||||
return decode(d, v)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeNil() error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != msgpcode.Nil {
|
||||
return fmt.Errorf("msgpack: invalid code=%x decoding nil", c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNilValue(v reflect.Value) error {
|
||||
err := d.DecodeNil()
|
||||
if v.IsNil() {
|
||||
return err
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBool() (bool, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return d.bool(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) bool(c byte) (bool, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return false, nil
|
||||
}
|
||||
if c == msgpcode.False {
|
||||
return false, nil
|
||||
}
|
||||
if c == msgpcode.True {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeDuration() (time.Duration, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return time.Duration(n), nil
|
||||
}
|
||||
|
||||
// DecodeInterface decodes value into interface. It returns following types:
|
||||
// - nil,
|
||||
// - bool,
|
||||
// - int8, int16, int32, int64,
|
||||
// - uint8, uint16, uint32, uint64,
|
||||
// - float32 and float64,
|
||||
// - string,
|
||||
// - []byte,
|
||||
// - slices of any of the above,
|
||||
// - maps of any of the above.
|
||||
//
|
||||
// DecodeInterface should be used only when you don't know the type of value
|
||||
// you are decoding. For example, if you are decoding number it is better to use
|
||||
// DecodeInt64 for negative numbers and DecodeUint64 for positive numbers.
|
||||
func (d *Decoder) DecodeInterface() (interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if msgpcode.IsFixedNum(c) {
|
||||
return int8(c), nil
|
||||
}
|
||||
if msgpcode.IsFixedMap(c) {
|
||||
err = d.s.UnreadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeMapDefault()
|
||||
}
|
||||
if msgpcode.IsFixedArray(c) {
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
if msgpcode.IsFixedString(c) {
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case msgpcode.Nil:
|
||||
return nil, nil
|
||||
case msgpcode.False, msgpcode.True:
|
||||
return d.bool(c)
|
||||
case msgpcode.Float:
|
||||
return d.float32(c)
|
||||
case msgpcode.Double:
|
||||
return d.float64(c)
|
||||
case msgpcode.Uint8:
|
||||
return d.uint8()
|
||||
case msgpcode.Uint16:
|
||||
return d.uint16()
|
||||
case msgpcode.Uint32:
|
||||
return d.uint32()
|
||||
case msgpcode.Uint64:
|
||||
return d.uint64()
|
||||
case msgpcode.Int8:
|
||||
return d.int8()
|
||||
case msgpcode.Int16:
|
||||
return d.int16()
|
||||
case msgpcode.Int32:
|
||||
return d.int32()
|
||||
case msgpcode.Int64:
|
||||
return d.int64()
|
||||
case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
|
||||
return d.bytes(c, nil)
|
||||
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32:
|
||||
return d.string(c)
|
||||
case msgpcode.Array16, msgpcode.Array32:
|
||||
return d.decodeSlice(c)
|
||||
case msgpcode.Map16, msgpcode.Map32:
|
||||
err = d.s.UnreadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeMapDefault()
|
||||
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
|
||||
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
|
||||
return d.decodeInterfaceExt(c)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
|
||||
}
|
||||
|
||||
// DecodeInterfaceLoose is like DecodeInterface except that:
|
||||
// - int8, int16, and int32 are converted to int64,
|
||||
// - uint8, uint16, and uint32 are converted to uint64,
|
||||
// - float32 is converted to float64.
|
||||
// - []byte is converted to string.
|
||||
func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if msgpcode.IsFixedNum(c) {
|
||||
return int64(int8(c)), nil
|
||||
}
|
||||
if msgpcode.IsFixedMap(c) {
|
||||
err = d.s.UnreadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeMapDefault()
|
||||
}
|
||||
if msgpcode.IsFixedArray(c) {
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
if msgpcode.IsFixedString(c) {
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case msgpcode.Nil:
|
||||
return nil, nil
|
||||
case msgpcode.False, msgpcode.True:
|
||||
return d.bool(c)
|
||||
case msgpcode.Float, msgpcode.Double:
|
||||
return d.float64(c)
|
||||
case msgpcode.Uint8, msgpcode.Uint16, msgpcode.Uint32, msgpcode.Uint64:
|
||||
return d.uint(c)
|
||||
case msgpcode.Int8, msgpcode.Int16, msgpcode.Int32, msgpcode.Int64:
|
||||
return d.int(c)
|
||||
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32,
|
||||
msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
|
||||
return d.string(c)
|
||||
case msgpcode.Array16, msgpcode.Array32:
|
||||
return d.decodeSlice(c)
|
||||
case msgpcode.Map16, msgpcode.Map32:
|
||||
err = d.s.UnreadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeMapDefault()
|
||||
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
|
||||
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
|
||||
return d.decodeInterfaceExt(c)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
|
||||
}
|
||||
|
||||
// Skip skips next value.
|
||||
func (d *Decoder) Skip() error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msgpcode.IsFixedNum(c) {
|
||||
return nil
|
||||
}
|
||||
if msgpcode.IsFixedMap(c) {
|
||||
return d.skipMap(c)
|
||||
}
|
||||
if msgpcode.IsFixedArray(c) {
|
||||
return d.skipSlice(c)
|
||||
}
|
||||
if msgpcode.IsFixedString(c) {
|
||||
return d.skipBytes(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case msgpcode.Nil, msgpcode.False, msgpcode.True:
|
||||
return nil
|
||||
case msgpcode.Uint8, msgpcode.Int8:
|
||||
return d.skipN(1)
|
||||
case msgpcode.Uint16, msgpcode.Int16:
|
||||
return d.skipN(2)
|
||||
case msgpcode.Uint32, msgpcode.Int32, msgpcode.Float:
|
||||
return d.skipN(4)
|
||||
case msgpcode.Uint64, msgpcode.Int64, msgpcode.Double:
|
||||
return d.skipN(8)
|
||||
case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
|
||||
return d.skipBytes(c)
|
||||
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32:
|
||||
return d.skipBytes(c)
|
||||
case msgpcode.Array16, msgpcode.Array32:
|
||||
return d.skipSlice(c)
|
||||
case msgpcode.Map16, msgpcode.Map32:
|
||||
return d.skipMap(c)
|
||||
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
|
||||
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
|
||||
return d.skipExt(c)
|
||||
}
|
||||
|
||||
return fmt.Errorf("msgpack: unknown code %x", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeRaw() (RawMessage, error) {
|
||||
d.rec = make([]byte, 0)
|
||||
if err := d.Skip(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg := RawMessage(d.rec)
|
||||
d.rec = nil
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// PeekCode returns the next MessagePack code without advancing the reader.
|
||||
// Subpackage msgpack/codes defines the list of available msgpcode.
|
||||
func (d *Decoder) PeekCode() (byte, error) {
|
||||
c, err := d.s.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c, d.s.UnreadByte()
|
||||
}
|
||||
|
||||
// ReadFull reads exactly len(buf) bytes into the buf.
|
||||
func (d *Decoder) ReadFull(buf []byte) error {
|
||||
_, err := readN(d.r, buf, len(buf))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) hasNilCode() bool {
|
||||
code, err := d.PeekCode()
|
||||
return err == nil && code == msgpcode.Nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readCode() (byte, error) {
|
||||
c, err := d.s.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if d.rec != nil {
|
||||
d.rec = append(d.rec, c)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readFull(b []byte) error {
|
||||
_, err := io.ReadFull(d.r, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.rec != nil {
|
||||
d.rec = append(d.rec, b...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readN(n int) ([]byte, error) {
|
||||
var err error
|
||||
if d.flags&disableAllocLimitFlag != 0 {
|
||||
d.buf, err = readN(d.r, d.buf, n)
|
||||
} else {
|
||||
d.buf, err = readNGrow(d.r, d.buf, n)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.rec != nil {
|
||||
// TODO: read directly into d.rec?
|
||||
d.rec = append(d.rec, d.buf...)
|
||||
}
|
||||
return d.buf, nil
|
||||
}
|
||||
|
||||
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
|
||||
if b == nil {
|
||||
if n == 0 {
|
||||
return make([]byte, 0), nil
|
||||
}
|
||||
b = make([]byte, 0, n)
|
||||
}
|
||||
|
||||
if n > cap(b) {
|
||||
b = append(b, make([]byte, n-len(b))...)
|
||||
} else if n <= cap(b) {
|
||||
b = b[:n]
|
||||
}
|
||||
|
||||
_, err := io.ReadFull(r, b)
|
||||
return b, err
|
||||
}
|
||||
|
||||
func readNGrow(r io.Reader, b []byte, n int) ([]byte, error) {
|
||||
if b == nil {
|
||||
if n == 0 {
|
||||
return make([]byte, 0), nil
|
||||
}
|
||||
switch {
|
||||
case n < 64:
|
||||
b = make([]byte, 0, 64)
|
||||
case n <= bytesAllocLimit:
|
||||
b = make([]byte, 0, n)
|
||||
default:
|
||||
b = make([]byte, 0, bytesAllocLimit)
|
||||
}
|
||||
}
|
||||
|
||||
if n <= cap(b) {
|
||||
b = b[:n]
|
||||
_, err := io.ReadFull(r, b)
|
||||
return b, err
|
||||
}
|
||||
b = b[:cap(b)]
|
||||
|
||||
var pos int
|
||||
for {
|
||||
alloc := min(n-len(b), bytesAllocLimit)
|
||||
b = append(b, make([]byte, alloc)...)
|
||||
|
||||
_, err := io.ReadFull(r, b[pos:])
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
if len(b) == n {
|
||||
break
|
||||
}
|
||||
pos = len(b)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func min(a, b int) int { //nolint:unparam
|
||||
if a <= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
356
vendor/github.com/vmihailenco/msgpack/v5/decode_map.go
generated
vendored
Normal file
356
vendor/github.com/vmihailenco/msgpack/v5/decode_map.go
generated
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
var errArrayStruct = errors.New("msgpack: number of fields in array-encoded struct has changed")
|
||||
|
||||
var (
|
||||
mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil))
|
||||
mapStringStringType = mapStringStringPtrType.Elem()
|
||||
mapStringBoolPtrType = reflect.TypeOf((*map[string]bool)(nil))
|
||||
mapStringBoolType = mapStringBoolPtrType.Elem()
|
||||
)
|
||||
|
||||
var (
|
||||
mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil))
|
||||
mapStringInterfaceType = mapStringInterfacePtrType.Elem()
|
||||
)
|
||||
|
||||
func decodeMapValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typ := v.Type()
|
||||
if n == -1 {
|
||||
v.Set(reflect.Zero(typ))
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.IsNil() {
|
||||
ln := n
|
||||
if d.flags&disableAllocLimitFlag == 0 {
|
||||
ln = min(ln, maxMapSize)
|
||||
}
|
||||
v.Set(reflect.MakeMapWithSize(typ, ln))
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return d.decodeTypedMapValue(v, n)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMapDefault() (interface{}, error) {
|
||||
if d.mapDecoder != nil {
|
||||
return d.mapDecoder(d)
|
||||
}
|
||||
return d.DecodeMap()
|
||||
}
|
||||
|
||||
// DecodeMapLen decodes map length. Length is -1 when map is nil.
|
||||
func (d *Decoder) DecodeMapLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if msgpcode.IsExt(c) {
|
||||
if err = d.skipExtHeader(c); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
c, err = d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return d.mapLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) mapLen(c byte) (int, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return -1, nil
|
||||
}
|
||||
if c >= msgpcode.FixedMapLow && c <= msgpcode.FixedMapHigh {
|
||||
return int(c & msgpcode.FixedMapMask), nil
|
||||
}
|
||||
if c == msgpcode.Map16 {
|
||||
size, err := d.uint16()
|
||||
return int(size), err
|
||||
}
|
||||
if c == msgpcode.Map32 {
|
||||
size, err := d.uint32()
|
||||
return int(size), err
|
||||
}
|
||||
return 0, unexpectedCodeError{code: c, hint: "map length"}
|
||||
}
|
||||
|
||||
func decodeMapStringStringValue(d *Decoder, v reflect.Value) error {
|
||||
mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string)
|
||||
return d.decodeMapStringStringPtr(mptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
|
||||
size, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if size == -1 {
|
||||
*ptr = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
m := *ptr
|
||||
if m == nil {
|
||||
ln := size
|
||||
if d.flags&disableAllocLimitFlag == 0 {
|
||||
ln = min(size, maxMapSize)
|
||||
}
|
||||
*ptr = make(map[string]string, ln)
|
||||
m = *ptr
|
||||
}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
mk, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mv, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m[mk] = mv
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error {
|
||||
ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{})
|
||||
return d.decodeMapStringInterfacePtr(ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error {
|
||||
m, err := d.DecodeMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ptr = m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeMap() (map[string]interface{}, error) {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
m := make(map[string]interface{}, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
mk, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mv, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m[mk] = mv
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUntypedMap() (map[interface{}]interface{}, error) {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
m := make(map[interface{}]interface{}, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
mk, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mv, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m[mk] = mv
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DecodeTypedMap decodes a typed map. Typed map is a map that has a fixed type for keys and values.
|
||||
// Key and value types may be different.
|
||||
func (d *Decoder) DecodeTypedMap() (interface{}, error) {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
key, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyType := reflect.TypeOf(key)
|
||||
valueType := reflect.TypeOf(value)
|
||||
|
||||
if !keyType.Comparable() {
|
||||
return nil, fmt.Errorf("msgpack: unsupported map key: %s", keyType.String())
|
||||
}
|
||||
|
||||
mapType := reflect.MapOf(keyType, valueType)
|
||||
|
||||
ln := n
|
||||
if d.flags&disableAllocLimitFlag == 0 {
|
||||
ln = min(ln, maxMapSize)
|
||||
}
|
||||
|
||||
mapValue := reflect.MakeMapWithSize(mapType, ln)
|
||||
mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
|
||||
|
||||
n--
|
||||
if err := d.decodeTypedMapValue(mapValue, n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapValue.Interface(), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeTypedMapValue(v reflect.Value, n int) error {
|
||||
var (
|
||||
typ = v.Type()
|
||||
keyType = typ.Key()
|
||||
valueType = typ.Elem()
|
||||
)
|
||||
for i := 0; i < n; i++ {
|
||||
mk := d.newValue(keyType).Elem()
|
||||
if err := d.DecodeValue(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mv := d.newValue(valueType).Elem()
|
||||
if err := d.DecodeValue(mv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.SetMapIndex(mk, mv)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipMap(c byte) error {
|
||||
n, err := d.mapLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeStructValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := d.mapLen(c)
|
||||
if err == nil {
|
||||
return d.decodeStruct(v, n)
|
||||
}
|
||||
|
||||
var err2 error
|
||||
n, err2 = d.arrayLen(c)
|
||||
if err2 != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n <= 0 {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
fields := structs.Fields(v.Type(), d.structTag)
|
||||
if n != len(fields.List) {
|
||||
return errArrayStruct
|
||||
}
|
||||
|
||||
for _, f := range fields.List {
|
||||
if err := f.DecodeValue(d, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStruct(v reflect.Value, n int) error {
|
||||
if n == -1 {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
fields := structs.Fields(v.Type(), d.structTag)
|
||||
for i := 0; i < n; i++ {
|
||||
name, err := d.decodeStringTemp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f := fields.Map[name]; f != nil {
|
||||
if err := f.DecodeValue(d, v); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if d.flags&disallowUnknownFieldsFlag != 0 {
|
||||
return fmt.Errorf("msgpack: unknown field %q", name)
|
||||
}
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
295
vendor/github.com/vmihailenco/msgpack/v5/decode_number.go
generated
vendored
Normal file
295
vendor/github.com/vmihailenco/msgpack/v5/decode_number.go
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
func (d *Decoder) skipN(n int) error {
|
||||
_, err := d.readN(n)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint8() (uint8, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int8() (int8, error) {
|
||||
n, err := d.uint8()
|
||||
return int8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint16() (uint16, error) {
|
||||
b, err := d.readN(2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return (uint16(b[0]) << 8) | uint16(b[1]), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int16() (int16, error) {
|
||||
n, err := d.uint16()
|
||||
return int16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint32() (uint32, error) {
|
||||
b, err := d.readN(4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n := (uint32(b[0]) << 24) |
|
||||
(uint32(b[1]) << 16) |
|
||||
(uint32(b[2]) << 8) |
|
||||
uint32(b[3])
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int32() (int32, error) {
|
||||
n, err := d.uint32()
|
||||
return int32(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint64() (uint64, error) {
|
||||
b, err := d.readN(8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n := (uint64(b[0]) << 56) |
|
||||
(uint64(b[1]) << 48) |
|
||||
(uint64(b[2]) << 40) |
|
||||
(uint64(b[3]) << 32) |
|
||||
(uint64(b[4]) << 24) |
|
||||
(uint64(b[5]) << 16) |
|
||||
(uint64(b[6]) << 8) |
|
||||
uint64(b[7])
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int64() (int64, error) {
|
||||
n, err := d.uint64()
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// DecodeUint64 decodes msgpack int8/16/32/64 and uint8/16/32/64
|
||||
// into Go uint64.
|
||||
func (d *Decoder) DecodeUint64() (uint64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.uint(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) uint(c byte) (uint64, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return 0, nil
|
||||
}
|
||||
if msgpcode.IsFixedNum(c) {
|
||||
return uint64(int8(c)), nil
|
||||
}
|
||||
switch c {
|
||||
case msgpcode.Uint8:
|
||||
n, err := d.uint8()
|
||||
return uint64(n), err
|
||||
case msgpcode.Int8:
|
||||
n, err := d.int8()
|
||||
return uint64(n), err
|
||||
case msgpcode.Uint16:
|
||||
n, err := d.uint16()
|
||||
return uint64(n), err
|
||||
case msgpcode.Int16:
|
||||
n, err := d.int16()
|
||||
return uint64(n), err
|
||||
case msgpcode.Uint32:
|
||||
n, err := d.uint32()
|
||||
return uint64(n), err
|
||||
case msgpcode.Int32:
|
||||
n, err := d.int32()
|
||||
return uint64(n), err
|
||||
case msgpcode.Uint64, msgpcode.Int64:
|
||||
return d.uint64()
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c)
|
||||
}
|
||||
|
||||
// DecodeInt64 decodes msgpack int8/16/32/64 and uint8/16/32/64
|
||||
// into Go int64.
|
||||
func (d *Decoder) DecodeInt64() (int64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.int(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) int(c byte) (int64, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return 0, nil
|
||||
}
|
||||
if msgpcode.IsFixedNum(c) {
|
||||
return int64(int8(c)), nil
|
||||
}
|
||||
switch c {
|
||||
case msgpcode.Uint8:
|
||||
n, err := d.uint8()
|
||||
return int64(n), err
|
||||
case msgpcode.Int8:
|
||||
n, err := d.uint8()
|
||||
return int64(int8(n)), err
|
||||
case msgpcode.Uint16:
|
||||
n, err := d.uint16()
|
||||
return int64(n), err
|
||||
case msgpcode.Int16:
|
||||
n, err := d.uint16()
|
||||
return int64(int16(n)), err
|
||||
case msgpcode.Uint32:
|
||||
n, err := d.uint32()
|
||||
return int64(n), err
|
||||
case msgpcode.Int32:
|
||||
n, err := d.uint32()
|
||||
return int64(int32(n)), err
|
||||
case msgpcode.Uint64, msgpcode.Int64:
|
||||
n, err := d.uint64()
|
||||
return int64(n), err
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeFloat32() (float32, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.float32(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) float32(c byte) (float32, error) {
|
||||
if c == msgpcode.Float {
|
||||
n, err := d.uint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return math.Float32frombits(n), nil
|
||||
}
|
||||
|
||||
n, err := d.int(c)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
|
||||
}
|
||||
return float32(n), nil
|
||||
}
|
||||
|
||||
// DecodeFloat64 decodes msgpack float32/64 into Go float64.
|
||||
func (d *Decoder) DecodeFloat64() (float64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.float64(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) float64(c byte) (float64, error) {
|
||||
switch c {
|
||||
case msgpcode.Float:
|
||||
n, err := d.float32(c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float64(n), nil
|
||||
case msgpcode.Double:
|
||||
n, err := d.uint64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return math.Float64frombits(n), nil
|
||||
}
|
||||
|
||||
n, err := d.int(c)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
|
||||
}
|
||||
return float64(n), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint() (uint, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint8() (uint8, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint16() (uint16, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint32() (uint32, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint32(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt() (int, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt8() (int8, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt16() (int16, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt32() (int32, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int32(n), err
|
||||
}
|
||||
|
||||
func decodeFloat32Value(d *Decoder, v reflect.Value) error {
|
||||
f, err := d.DecodeFloat32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetFloat(float64(f))
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeFloat64Value(d *Decoder, v reflect.Value) error {
|
||||
f, err := d.DecodeFloat64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetFloat(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt64Value(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetInt(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUint64Value(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeUint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetUint(n)
|
||||
return nil
|
||||
}
|
||||
157
vendor/github.com/vmihailenco/msgpack/v5/decode_query.go
generated
vendored
Normal file
157
vendor/github.com/vmihailenco/msgpack/v5/decode_query.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
type queryResult struct {
|
||||
query string
|
||||
key string
|
||||
values []interface{}
|
||||
hasAsterisk bool
|
||||
}
|
||||
|
||||
func (q *queryResult) nextKey() {
|
||||
ind := strings.IndexByte(q.query, '.')
|
||||
if ind == -1 {
|
||||
q.key = q.query
|
||||
q.query = ""
|
||||
return
|
||||
}
|
||||
q.key = q.query[:ind]
|
||||
q.query = q.query[ind+1:]
|
||||
}
|
||||
|
||||
// Query extracts data specified by the query from the msgpack stream skipping
|
||||
// any other data. Query consists of map keys and array indexes separated with dot,
|
||||
// e.g. key1.0.key2.
|
||||
func (d *Decoder) Query(query string) ([]interface{}, error) {
|
||||
res := queryResult{
|
||||
query: query,
|
||||
}
|
||||
if err := d.query(&res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.values, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) query(q *queryResult) error {
|
||||
q.nextKey()
|
||||
if q.key == "" {
|
||||
v, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.values = append(q.values, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
code, err := d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code):
|
||||
err = d.queryMapKey(q)
|
||||
case code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code):
|
||||
err = d.queryArrayIndex(q)
|
||||
default:
|
||||
err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) queryMapKey(q *queryResult) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
key, err := d.decodeStringTemp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if key == q.key {
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
if q.hasAsterisk {
|
||||
return d.skipNext((n - i - 1) * 2)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) queryArrayIndex(q *queryResult) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if q.key == "*" {
|
||||
q.hasAsterisk = true
|
||||
|
||||
query := q.query
|
||||
for i := 0; i < n; i++ {
|
||||
q.query = query
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
q.hasAsterisk = false
|
||||
return nil
|
||||
}
|
||||
|
||||
ind, err := strconv.Atoi(q.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if i == ind {
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
if q.hasAsterisk {
|
||||
return d.skipNext(n - i - 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipNext(n int) error {
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
198
vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go
generated
vendored
Normal file
198
vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
|
||||
|
||||
// DecodeArrayLen decodes array length. Length is -1 when array is nil.
|
||||
func (d *Decoder) DecodeArrayLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.arrayLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) arrayLen(c byte) (int, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return -1, nil
|
||||
} else if c >= msgpcode.FixedArrayLow && c <= msgpcode.FixedArrayHigh {
|
||||
return int(c & msgpcode.FixedArrayMask), nil
|
||||
}
|
||||
switch c {
|
||||
case msgpcode.Array16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case msgpcode.Array32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c)
|
||||
}
|
||||
|
||||
func decodeStringSliceValue(d *Decoder, v reflect.Value) error {
|
||||
ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
|
||||
return d.decodeStringSlicePtr(ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ss := makeStrings(*ptr, n, d.flags&disableAllocLimitFlag != 0)
|
||||
for i := 0; i < n; i++ {
|
||||
s, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss = append(ss, s)
|
||||
}
|
||||
*ptr = ss
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeStrings(s []string, n int, noLimit bool) []string {
|
||||
if !noLimit && n > sliceAllocLimit {
|
||||
n = sliceAllocLimit
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
return make([]string, 0, n)
|
||||
}
|
||||
|
||||
if cap(s) >= n {
|
||||
return s[:0]
|
||||
}
|
||||
|
||||
s = s[:cap(s)]
|
||||
s = append(s, make([]string, n-len(s))...)
|
||||
return s[:0]
|
||||
}
|
||||
|
||||
func decodeSliceValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return nil
|
||||
}
|
||||
if n == 0 && v.IsNil() {
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Cap() >= n {
|
||||
v.Set(v.Slice(0, n))
|
||||
} else if v.Len() < v.Cap() {
|
||||
v.Set(v.Slice(0, v.Cap()))
|
||||
}
|
||||
|
||||
noLimit := d.flags&disableAllocLimitFlag != 1
|
||||
|
||||
if noLimit && n > v.Len() {
|
||||
v.Set(growSliceValue(v, n, noLimit))
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if !noLimit && i >= v.Len() {
|
||||
v.Set(growSliceValue(v, n, noLimit))
|
||||
}
|
||||
|
||||
elem := v.Index(i)
|
||||
if err := d.DecodeValue(elem); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func growSliceValue(v reflect.Value, n int, noLimit bool) reflect.Value {
|
||||
diff := n - v.Len()
|
||||
if !noLimit && diff > sliceAllocLimit {
|
||||
diff = sliceAllocLimit
|
||||
}
|
||||
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
|
||||
return v
|
||||
}
|
||||
|
||||
func decodeArrayValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
if n > v.Len() {
|
||||
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
sv := v.Index(i)
|
||||
if err := d.DecodeValue(sv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeSlice() ([]interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeSlice(c byte) ([]interface{}, error) {
|
||||
n, err := d.arrayLen(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
s := make([]interface{}, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
v, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s = append(s, v)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipSlice(c byte) error {
|
||||
n, err := d.arrayLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
192
vendor/github.com/vmihailenco/msgpack/v5/decode_string.go
generated
vendored
Normal file
192
vendor/github.com/vmihailenco/msgpack/v5/decode_string.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
func (d *Decoder) bytesLen(c byte) (int, error) {
|
||||
if c == msgpcode.Nil {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
if msgpcode.IsFixedString(c) {
|
||||
return int(c & msgpcode.FixedStrMask), nil
|
||||
}
|
||||
|
||||
switch c {
|
||||
case msgpcode.Str8, msgpcode.Bin8:
|
||||
n, err := d.uint8()
|
||||
return int(n), err
|
||||
case msgpcode.Str16, msgpcode.Bin16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case msgpcode.Str32, msgpcode.Bin32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding string/bytes length", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeString() (string, error) {
|
||||
if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 {
|
||||
return d.decodeInternedString(intern)
|
||||
}
|
||||
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) string(c byte) (string, error) {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.stringWithLen(n)
|
||||
}
|
||||
|
||||
func (d *Decoder) stringWithLen(n int) (string, error) {
|
||||
if n <= 0 {
|
||||
return "", nil
|
||||
}
|
||||
b, err := d.readN(n)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func decodeStringValue(d *Decoder, v reflect.Value) error {
|
||||
s, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetString(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBytesLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.bytesLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBytes() ([]byte, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.bytes(c, nil)
|
||||
}
|
||||
|
||||
func (d *Decoder) bytes(c byte, b []byte) ([]byte, error) {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
return readN(d.r, b, n)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStringTemp() (string, error) {
|
||||
if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 {
|
||||
return d.decodeInternedString(intern)
|
||||
}
|
||||
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n == -1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
b, err := d.readN(n)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return bytesToString(b), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBytesPtr(ptr *[]byte) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.bytesPtr(c, ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) bytesPtr(c byte, ptr *[]byte) error {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
*ptr = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
*ptr, err = readN(d.r, *ptr, n)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) skipBytes(c byte) error {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
return d.skipN(n)
|
||||
}
|
||||
|
||||
func decodeBytesValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := d.bytes(c, v.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.SetBytes(b)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeByteArrayValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
if n > v.Len() {
|
||||
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
|
||||
}
|
||||
|
||||
b := v.Slice(0, n).Bytes()
|
||||
return d.readFull(b)
|
||||
}
|
||||
46
vendor/github.com/vmihailenco/msgpack/v5/decode_typgen.go
generated
vendored
Normal file
46
vendor/github.com/vmihailenco/msgpack/v5/decode_typgen.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var cachedValues struct {
|
||||
m map[reflect.Type]chan reflect.Value
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func cachedValue(t reflect.Type) reflect.Value {
|
||||
cachedValues.RLock()
|
||||
ch := cachedValues.m[t]
|
||||
cachedValues.RUnlock()
|
||||
if ch != nil {
|
||||
return <-ch
|
||||
}
|
||||
|
||||
cachedValues.Lock()
|
||||
defer cachedValues.Unlock()
|
||||
if ch = cachedValues.m[t]; ch != nil {
|
||||
return <-ch
|
||||
}
|
||||
|
||||
ch = make(chan reflect.Value, 256)
|
||||
go func() {
|
||||
for {
|
||||
ch <- reflect.New(t)
|
||||
}
|
||||
}()
|
||||
if cachedValues.m == nil {
|
||||
cachedValues.m = make(map[reflect.Type]chan reflect.Value, 8)
|
||||
}
|
||||
cachedValues.m[t] = ch
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func (d *Decoder) newValue(t reflect.Type) reflect.Value {
|
||||
if d.flags&usePreallocateValues == 0 {
|
||||
return reflect.New(t)
|
||||
}
|
||||
|
||||
return cachedValue(t)
|
||||
}
|
||||
251
vendor/github.com/vmihailenco/msgpack/v5/decode_value.go
generated
vendored
Normal file
251
vendor/github.com/vmihailenco/msgpack/v5/decode_value.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
stringType = reflect.TypeOf((*string)(nil)).Elem()
|
||||
boolType = reflect.TypeOf((*bool)(nil)).Elem()
|
||||
)
|
||||
|
||||
var valueDecoders []decoderFunc
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
valueDecoders = []decoderFunc{
|
||||
reflect.Bool: decodeBoolValue,
|
||||
reflect.Int: decodeInt64Value,
|
||||
reflect.Int8: decodeInt64Value,
|
||||
reflect.Int16: decodeInt64Value,
|
||||
reflect.Int32: decodeInt64Value,
|
||||
reflect.Int64: decodeInt64Value,
|
||||
reflect.Uint: decodeUint64Value,
|
||||
reflect.Uint8: decodeUint64Value,
|
||||
reflect.Uint16: decodeUint64Value,
|
||||
reflect.Uint32: decodeUint64Value,
|
||||
reflect.Uint64: decodeUint64Value,
|
||||
reflect.Float32: decodeFloat32Value,
|
||||
reflect.Float64: decodeFloat64Value,
|
||||
reflect.Complex64: decodeUnsupportedValue,
|
||||
reflect.Complex128: decodeUnsupportedValue,
|
||||
reflect.Array: decodeArrayValue,
|
||||
reflect.Chan: decodeUnsupportedValue,
|
||||
reflect.Func: decodeUnsupportedValue,
|
||||
reflect.Interface: decodeInterfaceValue,
|
||||
reflect.Map: decodeMapValue,
|
||||
reflect.Ptr: decodeUnsupportedValue,
|
||||
reflect.Slice: decodeSliceValue,
|
||||
reflect.String: decodeStringValue,
|
||||
reflect.Struct: decodeStructValue,
|
||||
reflect.UnsafePointer: decodeUnsupportedValue,
|
||||
}
|
||||
}
|
||||
|
||||
func getDecoder(typ reflect.Type) decoderFunc {
|
||||
if v, ok := typeDecMap.Load(typ); ok {
|
||||
return v.(decoderFunc)
|
||||
}
|
||||
fn := _getDecoder(typ)
|
||||
typeDecMap.Store(typ, fn)
|
||||
return fn
|
||||
}
|
||||
|
||||
func _getDecoder(typ reflect.Type) decoderFunc {
|
||||
kind := typ.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
if _, ok := typeDecMap.Load(typ.Elem()); ok {
|
||||
return ptrValueDecoder(typ)
|
||||
}
|
||||
}
|
||||
|
||||
if typ.Implements(customDecoderType) {
|
||||
return nilAwareDecoder(typ, decodeCustomValue)
|
||||
}
|
||||
if typ.Implements(unmarshalerType) {
|
||||
return nilAwareDecoder(typ, unmarshalValue)
|
||||
}
|
||||
if typ.Implements(binaryUnmarshalerType) {
|
||||
return nilAwareDecoder(typ, unmarshalBinaryValue)
|
||||
}
|
||||
if typ.Implements(textUnmarshalerType) {
|
||||
return nilAwareDecoder(typ, unmarshalTextValue)
|
||||
}
|
||||
|
||||
// Addressable struct field value.
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PtrTo(typ)
|
||||
if ptr.Implements(customDecoderType) {
|
||||
return addrDecoder(nilAwareDecoder(typ, decodeCustomValue))
|
||||
}
|
||||
if ptr.Implements(unmarshalerType) {
|
||||
return addrDecoder(nilAwareDecoder(typ, unmarshalValue))
|
||||
}
|
||||
if ptr.Implements(binaryUnmarshalerType) {
|
||||
return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryValue))
|
||||
}
|
||||
if ptr.Implements(textUnmarshalerType) {
|
||||
return addrDecoder(nilAwareDecoder(typ, unmarshalTextValue))
|
||||
}
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
return ptrValueDecoder(typ)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
return decodeBytesValue
|
||||
}
|
||||
if elem == stringType {
|
||||
return decodeStringSliceValue
|
||||
}
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return decodeByteArrayValue
|
||||
}
|
||||
case reflect.Map:
|
||||
if typ.Key() == stringType {
|
||||
switch typ.Elem() {
|
||||
case stringType:
|
||||
return decodeMapStringStringValue
|
||||
case interfaceType:
|
||||
return decodeMapStringInterfaceValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return valueDecoders[kind]
|
||||
}
|
||||
|
||||
func ptrValueDecoder(typ reflect.Type) decoderFunc {
|
||||
decoder := getDecoder(typ.Elem())
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if d.hasNilCode() {
|
||||
if !v.IsNil() {
|
||||
v.Set(d.newValue(typ).Elem())
|
||||
}
|
||||
return d.DecodeNil()
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(d.newValue(typ.Elem()))
|
||||
}
|
||||
return decoder(d, v.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func addrDecoder(fn decoderFunc) decoderFunc {
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
|
||||
}
|
||||
return fn(d, v.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
func nilAwareDecoder(typ reflect.Type, fn decoderFunc) decoderFunc {
|
||||
if nilable(typ.Kind()) {
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if d.hasNilCode() {
|
||||
return d.decodeNilValue(v)
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(d.newValue(typ.Elem()))
|
||||
}
|
||||
return fn(d, v)
|
||||
}
|
||||
}
|
||||
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if d.hasNilCode() {
|
||||
return d.decodeNilValue(v)
|
||||
}
|
||||
return fn(d, v)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeBoolValue(d *Decoder, v reflect.Value) error {
|
||||
flag, err := d.DecodeBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetBool(flag)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInterfaceValue(d *Decoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return d.interfaceValue(v)
|
||||
}
|
||||
return d.DecodeValue(v.Elem())
|
||||
}
|
||||
|
||||
func (d *Decoder) interfaceValue(v reflect.Value) error {
|
||||
vv, err := d.decodeInterfaceCond()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if vv != nil {
|
||||
if v.Type() == errorType {
|
||||
if vv, ok := vv.(string); ok {
|
||||
v.Set(reflect.ValueOf(errors.New(vv)))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
v.Set(reflect.ValueOf(vv))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUnsupportedValue(d *Decoder, v reflect.Value) error {
|
||||
return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type())
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func decodeCustomValue(d *Decoder, v reflect.Value) error {
|
||||
decoder := v.Interface().(CustomDecoder)
|
||||
return decoder.DecodeMsgpack(d)
|
||||
}
|
||||
|
||||
func unmarshalValue(d *Decoder, v reflect.Value) error {
|
||||
var b []byte
|
||||
|
||||
d.rec = make([]byte, 0, 64)
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
b = d.rec
|
||||
d.rec = nil
|
||||
|
||||
unmarshaler := v.Interface().(Unmarshaler)
|
||||
return unmarshaler.UnmarshalMsgpack(b)
|
||||
}
|
||||
|
||||
func unmarshalBinaryValue(d *Decoder, v reflect.Value) error {
|
||||
data, err := d.DecodeBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unmarshaler := v.Interface().(encoding.BinaryUnmarshaler)
|
||||
return unmarshaler.UnmarshalBinary(data)
|
||||
}
|
||||
|
||||
func unmarshalTextValue(d *Decoder, v reflect.Value) error {
|
||||
data, err := d.DecodeBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unmarshaler := v.Interface().(encoding.TextUnmarshaler)
|
||||
return unmarshaler.UnmarshalText(data)
|
||||
}
|
||||
270
vendor/github.com/vmihailenco/msgpack/v5/encode.go
generated
vendored
Normal file
270
vendor/github.com/vmihailenco/msgpack/v5/encode.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
const (
|
||||
sortMapKeysFlag uint32 = 1 << iota
|
||||
arrayEncodedStructsFlag
|
||||
useCompactIntsFlag
|
||||
useCompactFloatsFlag
|
||||
useInternedStringsFlag
|
||||
omitEmptyFlag
|
||||
)
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
WriteByte(byte) error
|
||||
}
|
||||
|
||||
type byteWriter struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func newByteWriter(w io.Writer) byteWriter {
|
||||
return byteWriter{
|
||||
Writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (bw byteWriter) WriteByte(c byte) error {
|
||||
_, err := bw.Write([]byte{c})
|
||||
return err
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var encPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return NewEncoder(nil)
|
||||
},
|
||||
}
|
||||
|
||||
func GetEncoder() *Encoder {
|
||||
return encPool.Get().(*Encoder)
|
||||
}
|
||||
|
||||
func PutEncoder(enc *Encoder) {
|
||||
enc.w = nil
|
||||
encPool.Put(enc)
|
||||
}
|
||||
|
||||
// Marshal returns the MessagePack encoding of v.
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
enc := GetEncoder()
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc.Reset(&buf)
|
||||
|
||||
err := enc.Encode(v)
|
||||
b := buf.Bytes()
|
||||
|
||||
PutEncoder(enc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
|
||||
type Encoder struct {
|
||||
w writer
|
||||
dict map[string]int
|
||||
structTag string
|
||||
buf []byte
|
||||
timeBuf []byte
|
||||
flags uint32
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
e := &Encoder{
|
||||
buf: make([]byte, 9),
|
||||
}
|
||||
e.Reset(w)
|
||||
return e
|
||||
}
|
||||
|
||||
// Writer returns the Encoder's writer.
|
||||
func (e *Encoder) Writer() io.Writer {
|
||||
return e.w
|
||||
}
|
||||
|
||||
// Reset discards any buffered data, resets all state, and switches the writer to write to w.
|
||||
func (e *Encoder) Reset(w io.Writer) {
|
||||
e.ResetDict(w, nil)
|
||||
}
|
||||
|
||||
// ResetDict is like Reset, but also resets the dict.
|
||||
func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) {
|
||||
e.ResetWriter(w)
|
||||
e.flags = 0
|
||||
e.structTag = ""
|
||||
e.dict = dict
|
||||
}
|
||||
|
||||
func (e *Encoder) WithDict(dict map[string]int, fn func(*Encoder) error) error {
|
||||
oldDict := e.dict
|
||||
e.dict = dict
|
||||
err := fn(e)
|
||||
e.dict = oldDict
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) ResetWriter(w io.Writer) {
|
||||
e.dict = nil
|
||||
if bw, ok := w.(writer); ok {
|
||||
e.w = bw
|
||||
} else if w == nil {
|
||||
e.w = nil
|
||||
} else {
|
||||
e.w = newByteWriter(w)
|
||||
}
|
||||
}
|
||||
|
||||
// SetSortMapKeys causes the Encoder to encode map keys in increasing order.
|
||||
// Supported map types are:
|
||||
// - map[string]string
|
||||
// - map[string]bool
|
||||
// - map[string]interface{}
|
||||
func (e *Encoder) SetSortMapKeys(on bool) *Encoder {
|
||||
if on {
|
||||
e.flags |= sortMapKeysFlag
|
||||
} else {
|
||||
e.flags &= ^sortMapKeysFlag
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// SetCustomStructTag causes the Encoder to use a custom struct tag as
|
||||
// fallback option if there is no msgpack tag.
|
||||
func (e *Encoder) SetCustomStructTag(tag string) {
|
||||
e.structTag = tag
|
||||
}
|
||||
|
||||
// SetOmitEmpty causes the Encoder to omit empty values by default.
|
||||
func (e *Encoder) SetOmitEmpty(on bool) {
|
||||
if on {
|
||||
e.flags |= omitEmptyFlag
|
||||
} else {
|
||||
e.flags &= ^omitEmptyFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays.
|
||||
func (e *Encoder) UseArrayEncodedStructs(on bool) {
|
||||
if on {
|
||||
e.flags |= arrayEncodedStructsFlag
|
||||
} else {
|
||||
e.flags &= ^arrayEncodedStructsFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UseCompactEncoding causes the Encoder to chose the most compact encoding.
|
||||
// For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes.
|
||||
func (e *Encoder) UseCompactInts(on bool) {
|
||||
if on {
|
||||
e.flags |= useCompactIntsFlag
|
||||
} else {
|
||||
e.flags &= ^useCompactIntsFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UseCompactFloats causes the Encoder to chose a compact integer encoding
|
||||
// for floats that can be represented as integers.
|
||||
func (e *Encoder) UseCompactFloats(on bool) {
|
||||
if on {
|
||||
e.flags |= useCompactFloatsFlag
|
||||
} else {
|
||||
e.flags &= ^useCompactFloatsFlag
|
||||
}
|
||||
}
|
||||
|
||||
// UseInternedStrings causes the Encoder to intern strings.
|
||||
func (e *Encoder) UseInternedStrings(on bool) {
|
||||
if on {
|
||||
e.flags |= useInternedStringsFlag
|
||||
} else {
|
||||
e.flags &= ^useInternedStringsFlag
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) Encode(v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case nil:
|
||||
return e.EncodeNil()
|
||||
case string:
|
||||
return e.EncodeString(v)
|
||||
case []byte:
|
||||
return e.EncodeBytes(v)
|
||||
case int:
|
||||
return e.EncodeInt(int64(v))
|
||||
case int64:
|
||||
return e.encodeInt64Cond(v)
|
||||
case uint:
|
||||
return e.EncodeUint(uint64(v))
|
||||
case uint64:
|
||||
return e.encodeUint64Cond(v)
|
||||
case bool:
|
||||
return e.EncodeBool(v)
|
||||
case float32:
|
||||
return e.EncodeFloat32(v)
|
||||
case float64:
|
||||
return e.EncodeFloat64(v)
|
||||
case time.Duration:
|
||||
return e.encodeInt64Cond(int64(v))
|
||||
case time.Time:
|
||||
return e.EncodeTime(v)
|
||||
}
|
||||
return e.EncodeValue(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeMulti(v ...interface{}) error {
|
||||
for _, vv := range v {
|
||||
if err := e.Encode(vv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeValue(v reflect.Value) error {
|
||||
fn := getEncoder(v.Type())
|
||||
return fn(e, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeNil() error {
|
||||
return e.writeCode(msgpcode.Nil)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBool(value bool) error {
|
||||
if value {
|
||||
return e.writeCode(msgpcode.True)
|
||||
}
|
||||
return e.writeCode(msgpcode.False)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeDuration(d time.Duration) error {
|
||||
return e.EncodeInt(int64(d))
|
||||
}
|
||||
|
||||
func (e *Encoder) writeCode(c byte) error {
|
||||
return e.w.WriteByte(c)
|
||||
}
|
||||
|
||||
func (e *Encoder) write(b []byte) error {
|
||||
_, err := e.w.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) writeString(s string) error {
|
||||
_, err := e.w.Write(stringToBytes(s))
|
||||
return err
|
||||
}
|
||||
225
vendor/github.com/vmihailenco/msgpack/v5/encode_map.go
generated
vendored
Normal file
225
vendor/github.com/vmihailenco/msgpack/v5/encode_map.go
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
func encodeMapValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
if err := e.EncodeValue(iter.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.EncodeValue(iter.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeMapStringBoolValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := v.Convert(mapStringBoolType).Interface().(map[string]bool)
|
||||
if e.flags&sortMapKeysFlag != 0 {
|
||||
return e.encodeSortedMapStringBool(m)
|
||||
}
|
||||
|
||||
for mk, mv := range m {
|
||||
if err := e.EncodeString(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.EncodeBool(mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := v.Convert(mapStringStringType).Interface().(map[string]string)
|
||||
if e.flags&sortMapKeysFlag != 0 {
|
||||
return e.encodeSortedMapStringString(m)
|
||||
}
|
||||
|
||||
for mk, mv := range m {
|
||||
if err := e.EncodeString(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.EncodeString(mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
|
||||
if e.flags&sortMapKeysFlag != 0 {
|
||||
return e.EncodeMapSorted(m)
|
||||
}
|
||||
return e.EncodeMap(m)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeMap(m map[string]interface{}) error {
|
||||
if m == nil {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
if err := e.EncodeMapLen(len(m)); err != nil {
|
||||
return err
|
||||
}
|
||||
for mk, mv := range m {
|
||||
if err := e.EncodeString(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.Encode(mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error {
|
||||
if m == nil {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
if err := e.EncodeMapLen(len(m)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(m))
|
||||
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
if err := e.EncodeString(k); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.Encode(m[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSortedMapStringBool(m map[string]bool) error {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
err := e.EncodeString(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = e.EncodeBool(m[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
err := e.EncodeString(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = e.EncodeString(m[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeMapLen(l int) error {
|
||||
if l < 16 {
|
||||
return e.writeCode(msgpcode.FixedMapLow | byte(l))
|
||||
}
|
||||
if l <= math.MaxUint16 {
|
||||
return e.write2(msgpcode.Map16, uint16(l))
|
||||
}
|
||||
return e.write4(msgpcode.Map32, uint32(l))
|
||||
}
|
||||
|
||||
func encodeStructValue(e *Encoder, strct reflect.Value) error {
|
||||
structFields := structs.Fields(strct.Type(), e.structTag)
|
||||
if e.flags&arrayEncodedStructsFlag != 0 || structFields.AsArray {
|
||||
return encodeStructValueAsArray(e, strct, structFields.List)
|
||||
}
|
||||
fields := structFields.OmitEmpty(e, strct)
|
||||
|
||||
if err := e.EncodeMapLen(len(fields)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range fields {
|
||||
if err := e.EncodeString(f.name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.EncodeValue(e, strct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error {
|
||||
if err := e.EncodeArrayLen(len(fields)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, f := range fields {
|
||||
if err := f.EncodeValue(e, strct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
252
vendor/github.com/vmihailenco/msgpack/v5/encode_number.go
generated
vendored
Normal file
252
vendor/github.com/vmihailenco/msgpack/v5/encode_number.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
// EncodeUint8 encodes an uint8 in 2 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeUint8(n uint8) error {
|
||||
return e.write1(msgpcode.Uint8, n)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeUint8Cond(n uint8) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeUint(uint64(n))
|
||||
}
|
||||
return e.EncodeUint8(n)
|
||||
}
|
||||
|
||||
// EncodeUint16 encodes an uint16 in 3 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeUint16(n uint16) error {
|
||||
return e.write2(msgpcode.Uint16, n)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeUint16Cond(n uint16) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeUint(uint64(n))
|
||||
}
|
||||
return e.EncodeUint16(n)
|
||||
}
|
||||
|
||||
// EncodeUint32 encodes an uint16 in 5 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeUint32(n uint32) error {
|
||||
return e.write4(msgpcode.Uint32, n)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeUint32Cond(n uint32) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeUint(uint64(n))
|
||||
}
|
||||
return e.EncodeUint32(n)
|
||||
}
|
||||
|
||||
// EncodeUint64 encodes an uint16 in 9 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeUint64(n uint64) error {
|
||||
return e.write8(msgpcode.Uint64, n)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeUint64Cond(n uint64) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeUint(n)
|
||||
}
|
||||
return e.EncodeUint64(n)
|
||||
}
|
||||
|
||||
// EncodeInt8 encodes an int8 in 2 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeInt8(n int8) error {
|
||||
return e.write1(msgpcode.Int8, uint8(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt8Cond(n int8) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeInt(int64(n))
|
||||
}
|
||||
return e.EncodeInt8(n)
|
||||
}
|
||||
|
||||
// EncodeInt16 encodes an int16 in 3 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeInt16(n int16) error {
|
||||
return e.write2(msgpcode.Int16, uint16(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt16Cond(n int16) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeInt(int64(n))
|
||||
}
|
||||
return e.EncodeInt16(n)
|
||||
}
|
||||
|
||||
// EncodeInt32 encodes an int32 in 5 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeInt32(n int32) error {
|
||||
return e.write4(msgpcode.Int32, uint32(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt32Cond(n int32) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeInt(int64(n))
|
||||
}
|
||||
return e.EncodeInt32(n)
|
||||
}
|
||||
|
||||
// EncodeInt64 encodes an int64 in 9 bytes preserving type of the number.
|
||||
func (e *Encoder) EncodeInt64(n int64) error {
|
||||
return e.write8(msgpcode.Int64, uint64(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt64Cond(n int64) error {
|
||||
if e.flags&useCompactIntsFlag != 0 {
|
||||
return e.EncodeInt(n)
|
||||
}
|
||||
return e.EncodeInt64(n)
|
||||
}
|
||||
|
||||
// EncodeUnsignedNumber encodes an uint64 in 1, 2, 3, 5, or 9 bytes.
|
||||
// Type of the number is lost during encoding.
|
||||
func (e *Encoder) EncodeUint(n uint64) error {
|
||||
if n <= math.MaxInt8 {
|
||||
return e.w.WriteByte(byte(n))
|
||||
}
|
||||
if n <= math.MaxUint8 {
|
||||
return e.EncodeUint8(uint8(n))
|
||||
}
|
||||
if n <= math.MaxUint16 {
|
||||
return e.EncodeUint16(uint16(n))
|
||||
}
|
||||
if n <= math.MaxUint32 {
|
||||
return e.EncodeUint32(uint32(n))
|
||||
}
|
||||
return e.EncodeUint64(n)
|
||||
}
|
||||
|
||||
// EncodeNumber encodes an int64 in 1, 2, 3, 5, or 9 bytes.
|
||||
// Type of the number is lost during encoding.
|
||||
func (e *Encoder) EncodeInt(n int64) error {
|
||||
if n >= 0 {
|
||||
return e.EncodeUint(uint64(n))
|
||||
}
|
||||
if n >= int64(int8(msgpcode.NegFixedNumLow)) {
|
||||
return e.w.WriteByte(byte(n))
|
||||
}
|
||||
if n >= math.MinInt8 {
|
||||
return e.EncodeInt8(int8(n))
|
||||
}
|
||||
if n >= math.MinInt16 {
|
||||
return e.EncodeInt16(int16(n))
|
||||
}
|
||||
if n >= math.MinInt32 {
|
||||
return e.EncodeInt32(int32(n))
|
||||
}
|
||||
return e.EncodeInt64(n)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeFloat32(n float32) error {
|
||||
if e.flags&useCompactFloatsFlag != 0 {
|
||||
if float32(int64(n)) == n {
|
||||
return e.EncodeInt(int64(n))
|
||||
}
|
||||
}
|
||||
return e.write4(msgpcode.Float, math.Float32bits(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeFloat64(n float64) error {
|
||||
if e.flags&useCompactFloatsFlag != 0 {
|
||||
// Both NaN and Inf convert to int64(-0x8000000000000000)
|
||||
// If n is NaN then it never compares true with any other value
|
||||
// If n is Inf then it doesn't convert from int64 back to +/-Inf
|
||||
// In both cases the comparison works.
|
||||
if float64(int64(n)) == n {
|
||||
return e.EncodeInt(int64(n))
|
||||
}
|
||||
}
|
||||
return e.write8(msgpcode.Double, math.Float64bits(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) write1(code byte, n uint8) error {
|
||||
e.buf = e.buf[:2]
|
||||
e.buf[0] = code
|
||||
e.buf[1] = n
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write2(code byte, n uint16) error {
|
||||
e.buf = e.buf[:3]
|
||||
e.buf[0] = code
|
||||
e.buf[1] = byte(n >> 8)
|
||||
e.buf[2] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write4(code byte, n uint32) error {
|
||||
e.buf = e.buf[:5]
|
||||
e.buf[0] = code
|
||||
e.buf[1] = byte(n >> 24)
|
||||
e.buf[2] = byte(n >> 16)
|
||||
e.buf[3] = byte(n >> 8)
|
||||
e.buf[4] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write8(code byte, n uint64) error {
|
||||
e.buf = e.buf[:9]
|
||||
e.buf[0] = code
|
||||
e.buf[1] = byte(n >> 56)
|
||||
e.buf[2] = byte(n >> 48)
|
||||
e.buf[3] = byte(n >> 40)
|
||||
e.buf[4] = byte(n >> 32)
|
||||
e.buf[5] = byte(n >> 24)
|
||||
e.buf[6] = byte(n >> 16)
|
||||
e.buf[7] = byte(n >> 8)
|
||||
e.buf[8] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func encodeUintValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeUint(v.Uint())
|
||||
}
|
||||
|
||||
func encodeIntValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeInt(v.Int())
|
||||
}
|
||||
|
||||
func encodeUint8CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeUint8Cond(uint8(v.Uint()))
|
||||
}
|
||||
|
||||
func encodeUint16CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeUint16Cond(uint16(v.Uint()))
|
||||
}
|
||||
|
||||
func encodeUint32CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeUint32Cond(uint32(v.Uint()))
|
||||
}
|
||||
|
||||
func encodeUint64CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeUint64Cond(v.Uint())
|
||||
}
|
||||
|
||||
func encodeInt8CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeInt8Cond(int8(v.Int()))
|
||||
}
|
||||
|
||||
func encodeInt16CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeInt16Cond(int16(v.Int()))
|
||||
}
|
||||
|
||||
func encodeInt32CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeInt32Cond(int32(v.Int()))
|
||||
}
|
||||
|
||||
func encodeInt64CondValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeInt64Cond(v.Int())
|
||||
}
|
||||
|
||||
func encodeFloat32Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeFloat32(float32(v.Float()))
|
||||
}
|
||||
|
||||
func encodeFloat64Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeFloat64(v.Float())
|
||||
}
|
||||
139
vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go
generated
vendored
Normal file
139
vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
var stringSliceType = reflect.TypeOf(([]string)(nil))
|
||||
|
||||
func encodeStringValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeString(v.String())
|
||||
}
|
||||
|
||||
func encodeByteSliceValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeBytes(v.Bytes())
|
||||
}
|
||||
|
||||
func encodeByteArrayValue(e *Encoder, v reflect.Value) error {
|
||||
if err := e.EncodeBytesLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v.CanAddr() {
|
||||
b := v.Slice(0, v.Len()).Bytes()
|
||||
return e.write(b)
|
||||
}
|
||||
|
||||
e.buf = grow(e.buf, v.Len())
|
||||
reflect.Copy(reflect.ValueOf(e.buf), v)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func grow(b []byte, n int) []byte {
|
||||
if cap(b) >= n {
|
||||
return b[:n]
|
||||
}
|
||||
b = b[:cap(b)]
|
||||
b = append(b, make([]byte, n-len(b))...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBytesLen(l int) error {
|
||||
if l < 256 {
|
||||
return e.write1(msgpcode.Bin8, uint8(l))
|
||||
}
|
||||
if l <= math.MaxUint16 {
|
||||
return e.write2(msgpcode.Bin16, uint16(l))
|
||||
}
|
||||
return e.write4(msgpcode.Bin32, uint32(l))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStringLen(l int) error {
|
||||
if l < 32 {
|
||||
return e.writeCode(msgpcode.FixedStrLow | byte(l))
|
||||
}
|
||||
if l < 256 {
|
||||
return e.write1(msgpcode.Str8, uint8(l))
|
||||
}
|
||||
if l <= math.MaxUint16 {
|
||||
return e.write2(msgpcode.Str16, uint16(l))
|
||||
}
|
||||
return e.write4(msgpcode.Str32, uint32(l))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeString(v string) error {
|
||||
if intern := e.flags&useInternedStringsFlag != 0; intern || len(e.dict) > 0 {
|
||||
return e.encodeInternedString(v, intern)
|
||||
}
|
||||
return e.encodeNormalString(v)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeNormalString(v string) error {
|
||||
if err := e.encodeStringLen(len(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.writeString(v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBytes(v []byte) error {
|
||||
if v == nil {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
if err := e.EncodeBytesLen(len(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write(v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeArrayLen(l int) error {
|
||||
if l < 16 {
|
||||
return e.writeCode(msgpcode.FixedArrayLow | byte(l))
|
||||
}
|
||||
if l <= math.MaxUint16 {
|
||||
return e.write2(msgpcode.Array16, uint16(l))
|
||||
}
|
||||
return e.write4(msgpcode.Array32, uint32(l))
|
||||
}
|
||||
|
||||
func encodeStringSliceValue(e *Encoder, v reflect.Value) error {
|
||||
ss := v.Convert(stringSliceType).Interface().([]string)
|
||||
return e.encodeStringSlice(ss)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStringSlice(s []string) error {
|
||||
if s == nil {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
if err := e.EncodeArrayLen(len(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range s {
|
||||
if err := e.EncodeString(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeSliceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return encodeArrayValue(e, v)
|
||||
}
|
||||
|
||||
func encodeArrayValue(e *Encoder, v reflect.Value) error {
|
||||
l := v.Len()
|
||||
if err := e.EncodeArrayLen(l); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
if err := e.EncodeValue(v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
254
vendor/github.com/vmihailenco/msgpack/v5/encode_value.go
generated
vendored
Normal file
254
vendor/github.com/vmihailenco/msgpack/v5/encode_value.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var valueEncoders []encoderFunc
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
valueEncoders = []encoderFunc{
|
||||
reflect.Bool: encodeBoolValue,
|
||||
reflect.Int: encodeIntValue,
|
||||
reflect.Int8: encodeInt8CondValue,
|
||||
reflect.Int16: encodeInt16CondValue,
|
||||
reflect.Int32: encodeInt32CondValue,
|
||||
reflect.Int64: encodeInt64CondValue,
|
||||
reflect.Uint: encodeUintValue,
|
||||
reflect.Uint8: encodeUint8CondValue,
|
||||
reflect.Uint16: encodeUint16CondValue,
|
||||
reflect.Uint32: encodeUint32CondValue,
|
||||
reflect.Uint64: encodeUint64CondValue,
|
||||
reflect.Float32: encodeFloat32Value,
|
||||
reflect.Float64: encodeFloat64Value,
|
||||
reflect.Complex64: encodeUnsupportedValue,
|
||||
reflect.Complex128: encodeUnsupportedValue,
|
||||
reflect.Array: encodeArrayValue,
|
||||
reflect.Chan: encodeUnsupportedValue,
|
||||
reflect.Func: encodeUnsupportedValue,
|
||||
reflect.Interface: encodeInterfaceValue,
|
||||
reflect.Map: encodeMapValue,
|
||||
reflect.Ptr: encodeUnsupportedValue,
|
||||
reflect.Slice: encodeSliceValue,
|
||||
reflect.String: encodeStringValue,
|
||||
reflect.Struct: encodeStructValue,
|
||||
reflect.UnsafePointer: encodeUnsupportedValue,
|
||||
}
|
||||
}
|
||||
|
||||
func getEncoder(typ reflect.Type) encoderFunc {
|
||||
if v, ok := typeEncMap.Load(typ); ok {
|
||||
return v.(encoderFunc)
|
||||
}
|
||||
fn := _getEncoder(typ)
|
||||
typeEncMap.Store(typ, fn)
|
||||
return fn
|
||||
}
|
||||
|
||||
func _getEncoder(typ reflect.Type) encoderFunc {
|
||||
kind := typ.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
if _, ok := typeEncMap.Load(typ.Elem()); ok {
|
||||
return ptrEncoderFunc(typ)
|
||||
}
|
||||
}
|
||||
|
||||
if typ.Implements(customEncoderType) {
|
||||
return encodeCustomValue
|
||||
}
|
||||
if typ.Implements(marshalerType) {
|
||||
return marshalValue
|
||||
}
|
||||
if typ.Implements(binaryMarshalerType) {
|
||||
return marshalBinaryValue
|
||||
}
|
||||
if typ.Implements(textMarshalerType) {
|
||||
return marshalTextValue
|
||||
}
|
||||
|
||||
// Addressable struct field value.
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PtrTo(typ)
|
||||
if ptr.Implements(customEncoderType) {
|
||||
return encodeCustomValuePtr
|
||||
}
|
||||
if ptr.Implements(marshalerType) {
|
||||
return marshalValuePtr
|
||||
}
|
||||
if ptr.Implements(binaryMarshalerType) {
|
||||
return marshalBinaryValueAddr
|
||||
}
|
||||
if ptr.Implements(textMarshalerType) {
|
||||
return marshalTextValueAddr
|
||||
}
|
||||
}
|
||||
|
||||
if typ == errorType {
|
||||
return encodeErrorValue
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
return ptrEncoderFunc(typ)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
return encodeByteSliceValue
|
||||
}
|
||||
if elem == stringType {
|
||||
return encodeStringSliceValue
|
||||
}
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return encodeByteArrayValue
|
||||
}
|
||||
case reflect.Map:
|
||||
if typ.Key() == stringType {
|
||||
switch typ.Elem() {
|
||||
case stringType:
|
||||
return encodeMapStringStringValue
|
||||
case boolType:
|
||||
return encodeMapStringBoolValue
|
||||
case interfaceType:
|
||||
return encodeMapStringInterfaceValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return valueEncoders[kind]
|
||||
}
|
||||
|
||||
func ptrEncoderFunc(typ reflect.Type) encoderFunc {
|
||||
encoder := getEncoder(typ.Elem())
|
||||
return func(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return encoder(e, v.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func encodeCustomValuePtr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
encoder := v.Addr().Interface().(CustomEncoder)
|
||||
return encoder.EncodeMsgpack(e)
|
||||
}
|
||||
|
||||
func encodeCustomValue(e *Encoder, v reflect.Value) error {
|
||||
if nilable(v.Kind()) && v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
encoder := v.Interface().(CustomEncoder)
|
||||
return encoder.EncodeMsgpack(e)
|
||||
}
|
||||
|
||||
func marshalValuePtr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
return marshalValue(e, v.Addr())
|
||||
}
|
||||
|
||||
func marshalValue(e *Encoder, v reflect.Value) error {
|
||||
if nilable(v.Kind()) && v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
marshaler := v.Interface().(Marshaler)
|
||||
b, err := marshaler.MarshalMsgpack()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = e.w.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeBoolValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeBool(v.Bool())
|
||||
}
|
||||
|
||||
func encodeInterfaceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return e.EncodeValue(v.Elem())
|
||||
}
|
||||
|
||||
func encodeErrorValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return e.EncodeString(v.Interface().(error).Error())
|
||||
}
|
||||
|
||||
func encodeUnsupportedValue(e *Encoder, v reflect.Value) error {
|
||||
return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type())
|
||||
}
|
||||
|
||||
func nilable(kind reflect.Kind) bool {
|
||||
switch kind {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func nilableType(t reflect.Type) bool {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
return nilable(t.Kind())
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func marshalBinaryValueAddr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
return marshalBinaryValue(e, v.Addr())
|
||||
}
|
||||
|
||||
func marshalBinaryValue(e *Encoder, v reflect.Value) error {
|
||||
if nilable(v.Kind()) && v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
marshaler := v.Interface().(encoding.BinaryMarshaler)
|
||||
data, err := marshaler.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.EncodeBytes(data)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func marshalTextValueAddr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
return marshalTextValue(e, v.Addr())
|
||||
}
|
||||
|
||||
func marshalTextValue(e *Encoder, v reflect.Value) error {
|
||||
if nilable(v.Kind()) && v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
marshaler := v.Interface().(encoding.TextMarshaler)
|
||||
data, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.EncodeBytes(data)
|
||||
}
|
||||
303
vendor/github.com/vmihailenco/msgpack/v5/ext.go
generated
vendored
Normal file
303
vendor/github.com/vmihailenco/msgpack/v5/ext.go
generated
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
type extInfo struct {
|
||||
Type reflect.Type
|
||||
Decoder func(d *Decoder, v reflect.Value, extLen int) error
|
||||
}
|
||||
|
||||
var extTypes = make(map[int8]*extInfo)
|
||||
|
||||
type MarshalerUnmarshaler interface {
|
||||
Marshaler
|
||||
Unmarshaler
|
||||
}
|
||||
|
||||
func RegisterExt(extID int8, value MarshalerUnmarshaler) {
|
||||
RegisterExtEncoder(extID, value, func(e *Encoder, v reflect.Value) ([]byte, error) {
|
||||
marshaler := v.Interface().(Marshaler)
|
||||
return marshaler.MarshalMsgpack()
|
||||
})
|
||||
RegisterExtDecoder(extID, value, func(d *Decoder, v reflect.Value, extLen int) error {
|
||||
b, err := d.readN(extLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.Interface().(Unmarshaler).UnmarshalMsgpack(b)
|
||||
})
|
||||
}
|
||||
|
||||
func UnregisterExt(extID int8) {
|
||||
unregisterExtEncoder(extID)
|
||||
unregisterExtDecoder(extID)
|
||||
}
|
||||
|
||||
func RegisterExtEncoder(
|
||||
extID int8,
|
||||
value interface{},
|
||||
encoder func(enc *Encoder, v reflect.Value) ([]byte, error),
|
||||
) {
|
||||
unregisterExtEncoder(extID)
|
||||
|
||||
typ := reflect.TypeOf(value)
|
||||
extEncoder := makeExtEncoder(extID, typ, encoder)
|
||||
typeEncMap.Store(extID, typ)
|
||||
typeEncMap.Store(typ, extEncoder)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typeEncMap.Store(typ.Elem(), makeExtEncoderAddr(extEncoder))
|
||||
}
|
||||
}
|
||||
|
||||
func unregisterExtEncoder(extID int8) {
|
||||
t, ok := typeEncMap.Load(extID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
typeEncMap.Delete(extID)
|
||||
typ := t.(reflect.Type)
|
||||
typeEncMap.Delete(typ)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typeEncMap.Delete(typ.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtEncoder(
|
||||
extID int8,
|
||||
typ reflect.Type,
|
||||
encoder func(enc *Encoder, v reflect.Value) ([]byte, error),
|
||||
) encoderFunc {
|
||||
nilable := typ.Kind() == reflect.Ptr
|
||||
|
||||
return func(e *Encoder, v reflect.Value) error {
|
||||
if nilable && v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
b, err := encoder(e, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.EncodeExtHeader(extID, len(b)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.write(b)
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtEncoderAddr(extEncoder encoderFunc) encoderFunc {
|
||||
return func(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: EncodeExt(nonaddressable %T)", v.Interface())
|
||||
}
|
||||
return extEncoder(e, v.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterExtDecoder(
|
||||
extID int8,
|
||||
value interface{},
|
||||
decoder func(dec *Decoder, v reflect.Value, extLen int) error,
|
||||
) {
|
||||
unregisterExtDecoder(extID)
|
||||
|
||||
typ := reflect.TypeOf(value)
|
||||
extDecoder := makeExtDecoder(extID, typ, decoder)
|
||||
extTypes[extID] = &extInfo{
|
||||
Type: typ,
|
||||
Decoder: decoder,
|
||||
}
|
||||
|
||||
typeDecMap.Store(extID, typ)
|
||||
typeDecMap.Store(typ, extDecoder)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typeDecMap.Store(typ.Elem(), makeExtDecoderAddr(extDecoder))
|
||||
}
|
||||
}
|
||||
|
||||
func unregisterExtDecoder(extID int8) {
|
||||
t, ok := typeDecMap.Load(extID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
typeDecMap.Delete(extID)
|
||||
delete(extTypes, extID)
|
||||
typ := t.(reflect.Type)
|
||||
typeDecMap.Delete(typ)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typeDecMap.Delete(typ.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtDecoder(
|
||||
wantedExtID int8,
|
||||
typ reflect.Type,
|
||||
decoder func(d *Decoder, v reflect.Value, extLen int) error,
|
||||
) decoderFunc {
|
||||
return nilAwareDecoder(typ, func(d *Decoder, v reflect.Value) error {
|
||||
extID, extLen, err := d.DecodeExtHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if extID != wantedExtID {
|
||||
return fmt.Errorf("msgpack: got ext type=%d, wanted %d", extID, wantedExtID)
|
||||
}
|
||||
return decoder(d, v, extLen)
|
||||
})
|
||||
}
|
||||
|
||||
func makeExtDecoderAddr(extDecoder decoderFunc) decoderFunc {
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: DecodeExt(nonaddressable %T)", v.Interface())
|
||||
}
|
||||
return extDecoder(d, v.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeExtHeader(extID int8, extLen int) error {
|
||||
if err := e.encodeExtLen(extLen); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.w.WriteByte(byte(extID)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeExtLen(l int) error {
|
||||
switch l {
|
||||
case 1:
|
||||
return e.writeCode(msgpcode.FixExt1)
|
||||
case 2:
|
||||
return e.writeCode(msgpcode.FixExt2)
|
||||
case 4:
|
||||
return e.writeCode(msgpcode.FixExt4)
|
||||
case 8:
|
||||
return e.writeCode(msgpcode.FixExt8)
|
||||
case 16:
|
||||
return e.writeCode(msgpcode.FixExt16)
|
||||
}
|
||||
if l <= math.MaxUint8 {
|
||||
return e.write1(msgpcode.Ext8, uint8(l))
|
||||
}
|
||||
if l <= math.MaxUint16 {
|
||||
return e.write2(msgpcode.Ext16, uint16(l))
|
||||
}
|
||||
return e.write4(msgpcode.Ext32, uint32(l))
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeExtHeader() (extID int8, extLen int, err error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return d.extHeader(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) extHeader(c byte) (int8, int, error) {
|
||||
extLen, err := d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
extID, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int8(extID), extLen, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) parseExtLen(c byte) (int, error) {
|
||||
switch c {
|
||||
case msgpcode.FixExt1:
|
||||
return 1, nil
|
||||
case msgpcode.FixExt2:
|
||||
return 2, nil
|
||||
case msgpcode.FixExt4:
|
||||
return 4, nil
|
||||
case msgpcode.FixExt8:
|
||||
return 8, nil
|
||||
case msgpcode.FixExt16:
|
||||
return 16, nil
|
||||
case msgpcode.Ext8:
|
||||
n, err := d.uint8()
|
||||
return int(n), err
|
||||
case msgpcode.Ext16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case msgpcode.Ext32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
default:
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext len", c)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInterfaceExt(c byte) (interface{}, error) {
|
||||
extID, extLen, err := d.extHeader(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, ok := extTypes[extID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID)
|
||||
}
|
||||
|
||||
v := d.newValue(info.Type).Elem()
|
||||
if nilable(v.Kind()) && v.IsNil() {
|
||||
v.Set(d.newValue(info.Type.Elem()))
|
||||
}
|
||||
|
||||
if err := info.Decoder(d, v, extLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipExt(c byte) error {
|
||||
n, err := d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.skipN(n + 1)
|
||||
}
|
||||
|
||||
func (d *Decoder) skipExtHeader(c byte) error {
|
||||
// Read ext type.
|
||||
_, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Read ext body len.
|
||||
for i := 0; i < extHeaderLen(c); i++ {
|
||||
_, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extHeaderLen(c byte) int {
|
||||
switch c {
|
||||
case msgpcode.Ext8:
|
||||
return 1
|
||||
case msgpcode.Ext16:
|
||||
return 2
|
||||
case msgpcode.Ext32:
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
}
|
||||
236
vendor/github.com/vmihailenco/msgpack/v5/intern.go
generated
vendored
Normal file
236
vendor/github.com/vmihailenco/msgpack/v5/intern.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
const (
|
||||
minInternedStringLen = 3
|
||||
maxDictLen = math.MaxUint16
|
||||
)
|
||||
|
||||
var internedStringExtID = int8(math.MinInt8)
|
||||
|
||||
func init() {
|
||||
extTypes[internedStringExtID] = &extInfo{
|
||||
Type: stringType,
|
||||
Decoder: decodeInternedStringExt,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeInternedStringExt(d *Decoder, v reflect.Value, extLen int) error {
|
||||
idx, err := d.decodeInternedStringIndex(extLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := d.internedStringAtIndex(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.SetString(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func encodeInternedInterfaceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
v = v.Elem()
|
||||
if v.Kind() == reflect.String {
|
||||
return e.encodeInternedString(v.String(), true)
|
||||
}
|
||||
return e.EncodeValue(v)
|
||||
}
|
||||
|
||||
func encodeInternedStringValue(e *Encoder, v reflect.Value) error {
|
||||
return e.encodeInternedString(v.String(), true)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInternedString(s string, intern bool) error {
|
||||
// Interned string takes at least 3 bytes. Plain string 1 byte + string len.
|
||||
if idx, ok := e.dict[s]; ok {
|
||||
return e.encodeInternedStringIndex(idx)
|
||||
}
|
||||
|
||||
if intern && len(s) >= minInternedStringLen && len(e.dict) < maxDictLen {
|
||||
if e.dict == nil {
|
||||
e.dict = make(map[string]int)
|
||||
}
|
||||
idx := len(e.dict)
|
||||
e.dict[s] = idx
|
||||
}
|
||||
|
||||
return e.encodeNormalString(s)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInternedStringIndex(idx int) error {
|
||||
if idx <= math.MaxUint8 {
|
||||
if err := e.writeCode(msgpcode.FixExt1); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write1(byte(internedStringExtID), uint8(idx))
|
||||
}
|
||||
|
||||
if idx <= math.MaxUint16 {
|
||||
if err := e.writeCode(msgpcode.FixExt2); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write2(byte(internedStringExtID), uint16(idx))
|
||||
}
|
||||
|
||||
if uint64(idx) <= math.MaxUint32 {
|
||||
if err := e.writeCode(msgpcode.FixExt4); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write4(byte(internedStringExtID), uint32(idx))
|
||||
}
|
||||
|
||||
return fmt.Errorf("msgpack: interned string index=%d is too large", idx)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func decodeInternedInterfaceValue(d *Decoder, v reflect.Value) error {
|
||||
s, err := d.decodeInternedString(true)
|
||||
if err == nil {
|
||||
v.Set(reflect.ValueOf(s))
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
if _, ok := err.(unexpectedCodeError); !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := d.s.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
return decodeInterfaceValue(d, v)
|
||||
}
|
||||
|
||||
func decodeInternedStringValue(d *Decoder, v reflect.Value) error {
|
||||
s, err := d.decodeInternedString(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.SetString(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInternedString(intern bool) (string, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if msgpcode.IsFixedString(c) {
|
||||
n := int(c & msgpcode.FixedStrMask)
|
||||
return d.decodeInternedStringWithLen(n, intern)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case msgpcode.Nil:
|
||||
return "", nil
|
||||
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4:
|
||||
typeID, extLen, err := d.extHeader(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if typeID != internedStringExtID {
|
||||
err := fmt.Errorf("msgpack: got ext type=%d, wanted %d",
|
||||
typeID, internedStringExtID)
|
||||
return "", err
|
||||
}
|
||||
|
||||
idx, err := d.decodeInternedStringIndex(extLen)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return d.internedStringAtIndex(idx)
|
||||
case msgpcode.Str8, msgpcode.Bin8:
|
||||
n, err := d.uint8()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.decodeInternedStringWithLen(int(n), intern)
|
||||
case msgpcode.Str16, msgpcode.Bin16:
|
||||
n, err := d.uint16()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.decodeInternedStringWithLen(int(n), intern)
|
||||
case msgpcode.Str32, msgpcode.Bin32:
|
||||
n, err := d.uint32()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.decodeInternedStringWithLen(int(n), intern)
|
||||
}
|
||||
|
||||
return "", unexpectedCodeError{
|
||||
code: c,
|
||||
hint: "interned string",
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInternedStringIndex(extLen int) (int, error) {
|
||||
switch extLen {
|
||||
case 1:
|
||||
n, err := d.uint8()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(n), nil
|
||||
case 2:
|
||||
n, err := d.uint16()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(n), nil
|
||||
case 4:
|
||||
n, err := d.uint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
err := fmt.Errorf("msgpack: unsupported ext len=%d decoding interned string", extLen)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func (d *Decoder) internedStringAtIndex(idx int) (string, error) {
|
||||
if idx >= len(d.dict) {
|
||||
err := fmt.Errorf("msgpack: interned string at index=%d does not exist", idx)
|
||||
return "", err
|
||||
}
|
||||
return d.dict[idx], nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInternedStringWithLen(n int, intern bool) (string, error) {
|
||||
if n <= 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
s, err := d.stringWithLen(n)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if intern && len(s) >= minInternedStringLen && len(d.dict) < maxDictLen {
|
||||
d.dict = append(d.dict, s)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
52
vendor/github.com/vmihailenco/msgpack/v5/msgpack.go
generated
vendored
Normal file
52
vendor/github.com/vmihailenco/msgpack/v5/msgpack.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package msgpack
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Marshaler interface {
|
||||
MarshalMsgpack() ([]byte, error)
|
||||
}
|
||||
|
||||
type Unmarshaler interface {
|
||||
UnmarshalMsgpack([]byte) error
|
||||
}
|
||||
|
||||
type CustomEncoder interface {
|
||||
EncodeMsgpack(*Encoder) error
|
||||
}
|
||||
|
||||
type CustomDecoder interface {
|
||||
DecodeMsgpack(*Decoder) error
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type RawMessage []byte
|
||||
|
||||
var (
|
||||
_ CustomEncoder = (RawMessage)(nil)
|
||||
_ CustomDecoder = (*RawMessage)(nil)
|
||||
)
|
||||
|
||||
func (m RawMessage) EncodeMsgpack(enc *Encoder) error {
|
||||
return enc.write(m)
|
||||
}
|
||||
|
||||
func (m *RawMessage) DecodeMsgpack(dec *Decoder) error {
|
||||
msg, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type unexpectedCodeError struct {
|
||||
hint string
|
||||
code byte
|
||||
}
|
||||
|
||||
func (err unexpectedCodeError) Error() string {
|
||||
return fmt.Sprintf("msgpack: unexpected code=%x decoding %s", err.code, err.hint)
|
||||
}
|
||||
88
vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go
generated
vendored
Normal file
88
vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package msgpcode
|
||||
|
||||
var (
|
||||
PosFixedNumHigh byte = 0x7f
|
||||
NegFixedNumLow byte = 0xe0
|
||||
|
||||
Nil byte = 0xc0
|
||||
|
||||
False byte = 0xc2
|
||||
True byte = 0xc3
|
||||
|
||||
Float byte = 0xca
|
||||
Double byte = 0xcb
|
||||
|
||||
Uint8 byte = 0xcc
|
||||
Uint16 byte = 0xcd
|
||||
Uint32 byte = 0xce
|
||||
Uint64 byte = 0xcf
|
||||
|
||||
Int8 byte = 0xd0
|
||||
Int16 byte = 0xd1
|
||||
Int32 byte = 0xd2
|
||||
Int64 byte = 0xd3
|
||||
|
||||
FixedStrLow byte = 0xa0
|
||||
FixedStrHigh byte = 0xbf
|
||||
FixedStrMask byte = 0x1f
|
||||
Str8 byte = 0xd9
|
||||
Str16 byte = 0xda
|
||||
Str32 byte = 0xdb
|
||||
|
||||
Bin8 byte = 0xc4
|
||||
Bin16 byte = 0xc5
|
||||
Bin32 byte = 0xc6
|
||||
|
||||
FixedArrayLow byte = 0x90
|
||||
FixedArrayHigh byte = 0x9f
|
||||
FixedArrayMask byte = 0xf
|
||||
Array16 byte = 0xdc
|
||||
Array32 byte = 0xdd
|
||||
|
||||
FixedMapLow byte = 0x80
|
||||
FixedMapHigh byte = 0x8f
|
||||
FixedMapMask byte = 0xf
|
||||
Map16 byte = 0xde
|
||||
Map32 byte = 0xdf
|
||||
|
||||
FixExt1 byte = 0xd4
|
||||
FixExt2 byte = 0xd5
|
||||
FixExt4 byte = 0xd6
|
||||
FixExt8 byte = 0xd7
|
||||
FixExt16 byte = 0xd8
|
||||
Ext8 byte = 0xc7
|
||||
Ext16 byte = 0xc8
|
||||
Ext32 byte = 0xc9
|
||||
)
|
||||
|
||||
func IsFixedNum(c byte) bool {
|
||||
return c <= PosFixedNumHigh || c >= NegFixedNumLow
|
||||
}
|
||||
|
||||
func IsFixedMap(c byte) bool {
|
||||
return c >= FixedMapLow && c <= FixedMapHigh
|
||||
}
|
||||
|
||||
func IsFixedArray(c byte) bool {
|
||||
return c >= FixedArrayLow && c <= FixedArrayHigh
|
||||
}
|
||||
|
||||
func IsFixedString(c byte) bool {
|
||||
return c >= FixedStrLow && c <= FixedStrHigh
|
||||
}
|
||||
|
||||
func IsString(c byte) bool {
|
||||
return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32
|
||||
}
|
||||
|
||||
func IsBin(c byte) bool {
|
||||
return c == Bin8 || c == Bin16 || c == Bin32
|
||||
}
|
||||
|
||||
func IsFixedExt(c byte) bool {
|
||||
return c >= FixExt1 && c <= FixExt16
|
||||
}
|
||||
|
||||
func IsExt(c byte) bool {
|
||||
return IsFixedExt(c) || c == Ext8 || c == Ext16 || c == Ext32
|
||||
}
|
||||
4
vendor/github.com/vmihailenco/msgpack/v5/package.json
generated
vendored
Normal file
4
vendor/github.com/vmihailenco/msgpack/v5/package.json
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "msgpack",
|
||||
"version": "5.4.1"
|
||||
}
|
||||
13
vendor/github.com/vmihailenco/msgpack/v5/safe.go
generated
vendored
Normal file
13
vendor/github.com/vmihailenco/msgpack/v5/safe.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// +build appengine
|
||||
|
||||
package msgpack
|
||||
|
||||
// bytesToString converts byte slice to string.
|
||||
func bytesToString(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// stringToBytes converts string to byte slice.
|
||||
func stringToBytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
151
vendor/github.com/vmihailenco/msgpack/v5/time.go
generated
vendored
Normal file
151
vendor/github.com/vmihailenco/msgpack/v5/time.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
var timeExtID int8 = -1
|
||||
|
||||
func init() {
|
||||
RegisterExtEncoder(timeExtID, time.Time{}, timeEncoder)
|
||||
RegisterExtDecoder(timeExtID, time.Time{}, timeDecoder)
|
||||
}
|
||||
|
||||
func timeEncoder(e *Encoder, v reflect.Value) ([]byte, error) {
|
||||
return e.encodeTime(v.Interface().(time.Time)), nil
|
||||
}
|
||||
|
||||
func timeDecoder(d *Decoder, v reflect.Value, extLen int) error {
|
||||
tm, err := d.decodeTime(extLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tm.IsZero() {
|
||||
// Zero time does not have timezone information.
|
||||
tm = tm.UTC()
|
||||
}
|
||||
|
||||
ptr := v.Addr().Interface().(*time.Time)
|
||||
*ptr = tm
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeTime(tm time.Time) error {
|
||||
b := e.encodeTime(tm)
|
||||
if err := e.encodeExtLen(len(b)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.w.WriteByte(byte(timeExtID)); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write(b)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeTime(tm time.Time) []byte {
|
||||
if e.timeBuf == nil {
|
||||
e.timeBuf = make([]byte, 12)
|
||||
}
|
||||
|
||||
secs := uint64(tm.Unix())
|
||||
if secs>>34 == 0 {
|
||||
data := uint64(tm.Nanosecond())<<34 | secs
|
||||
|
||||
if data&0xffffffff00000000 == 0 {
|
||||
b := e.timeBuf[:4]
|
||||
binary.BigEndian.PutUint32(b, uint32(data))
|
||||
return b
|
||||
}
|
||||
|
||||
b := e.timeBuf[:8]
|
||||
binary.BigEndian.PutUint64(b, data)
|
||||
return b
|
||||
}
|
||||
|
||||
b := e.timeBuf[:12]
|
||||
binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond()))
|
||||
binary.BigEndian.PutUint64(b[4:], secs)
|
||||
return b
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeTime() (time.Time, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// Legacy format.
|
||||
if c == msgpcode.FixedArrayLow|2 {
|
||||
sec, err := d.DecodeInt64()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
nsec, err := d.DecodeInt64()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Unix(sec, nsec), nil
|
||||
}
|
||||
|
||||
if msgpcode.IsString(c) {
|
||||
s, err := d.string(c)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Parse(time.RFC3339Nano, s)
|
||||
}
|
||||
|
||||
extID, extLen, err := d.extHeader(c)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// NodeJS seems to use extID 13.
|
||||
if extID != timeExtID && extID != 13 {
|
||||
return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID)
|
||||
}
|
||||
|
||||
tm, err := d.decodeTime(extLen)
|
||||
if err != nil {
|
||||
return tm, err
|
||||
}
|
||||
|
||||
if tm.IsZero() {
|
||||
// Zero time does not have timezone information.
|
||||
return tm.UTC(), nil
|
||||
}
|
||||
return tm, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeTime(extLen int) (time.Time, error) {
|
||||
b, err := d.readN(extLen)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
switch len(b) {
|
||||
case 4:
|
||||
sec := binary.BigEndian.Uint32(b)
|
||||
return time.Unix(int64(sec), 0), nil
|
||||
case 8:
|
||||
sec := binary.BigEndian.Uint64(b)
|
||||
nsec := int64(sec >> 34)
|
||||
sec &= 0x00000003ffffffff
|
||||
return time.Unix(int64(sec), nsec), nil
|
||||
case 12:
|
||||
nsec := binary.BigEndian.Uint32(b)
|
||||
sec := binary.BigEndian.Uint64(b[4:])
|
||||
return time.Unix(int64(sec), int64(nsec)), nil
|
||||
default:
|
||||
err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen)
|
||||
return time.Time{}, err
|
||||
}
|
||||
}
|
||||
413
vendor/github.com/vmihailenco/msgpack/v5/types.go
generated
vendored
Normal file
413
vendor/github.com/vmihailenco/msgpack/v5/types.go
generated
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/vmihailenco/tagparser/v2"
|
||||
)
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
var (
|
||||
customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
|
||||
customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
|
||||
)
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
var (
|
||||
binaryMarshalerType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
|
||||
binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
var (
|
||||
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
type (
|
||||
encoderFunc func(*Encoder, reflect.Value) error
|
||||
decoderFunc func(*Decoder, reflect.Value) error
|
||||
)
|
||||
|
||||
var (
|
||||
typeEncMap sync.Map
|
||||
typeDecMap sync.Map
|
||||
)
|
||||
|
||||
// Register registers encoder and decoder functions for a value.
|
||||
// This is low level API and in most cases you should prefer implementing
|
||||
// CustomEncoder/CustomDecoder or Marshaler/Unmarshaler interfaces.
|
||||
func Register(value interface{}, enc encoderFunc, dec decoderFunc) {
|
||||
typ := reflect.TypeOf(value)
|
||||
if enc != nil {
|
||||
typeEncMap.Store(typ, enc)
|
||||
}
|
||||
if dec != nil {
|
||||
typeDecMap.Store(typ, dec)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const defaultStructTag = "msgpack"
|
||||
|
||||
var structs = newStructCache()
|
||||
|
||||
type structCache struct {
|
||||
m sync.Map
|
||||
}
|
||||
|
||||
type structCacheKey struct {
|
||||
typ reflect.Type
|
||||
tag string
|
||||
}
|
||||
|
||||
func newStructCache() *structCache {
|
||||
return new(structCache)
|
||||
}
|
||||
|
||||
func (m *structCache) Fields(typ reflect.Type, tag string) *fields {
|
||||
key := structCacheKey{tag: tag, typ: typ}
|
||||
|
||||
if v, ok := m.m.Load(key); ok {
|
||||
return v.(*fields)
|
||||
}
|
||||
|
||||
fs := getFields(typ, tag)
|
||||
m.m.Store(key, fs)
|
||||
|
||||
return fs
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type field struct {
|
||||
encoder encoderFunc
|
||||
decoder decoderFunc
|
||||
name string
|
||||
index []int
|
||||
omitEmpty bool
|
||||
}
|
||||
|
||||
func (f *field) Omit(e *Encoder, strct reflect.Value) bool {
|
||||
v, ok := fieldByIndex(strct, f.index)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
forced := e.flags&omitEmptyFlag != 0
|
||||
return (f.omitEmpty || forced) && e.isEmptyValue(v)
|
||||
}
|
||||
|
||||
func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
|
||||
v, ok := fieldByIndex(strct, f.index)
|
||||
if !ok {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return f.encoder(e, v)
|
||||
}
|
||||
|
||||
func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error {
|
||||
v := fieldByIndexAlloc(strct, f.index)
|
||||
return f.decoder(d, v)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type fields struct {
|
||||
Type reflect.Type
|
||||
Map map[string]*field
|
||||
List []*field
|
||||
AsArray bool
|
||||
|
||||
hasOmitEmpty bool
|
||||
}
|
||||
|
||||
func newFields(typ reflect.Type) *fields {
|
||||
return &fields{
|
||||
Type: typ,
|
||||
Map: make(map[string]*field, typ.NumField()),
|
||||
List: make([]*field, 0, typ.NumField()),
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *fields) Add(field *field) {
|
||||
fs.warnIfFieldExists(field.name)
|
||||
fs.Map[field.name] = field
|
||||
fs.List = append(fs.List, field)
|
||||
if field.omitEmpty {
|
||||
fs.hasOmitEmpty = true
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *fields) warnIfFieldExists(name string) {
|
||||
if _, ok := fs.Map[name]; ok {
|
||||
log.Printf("msgpack: %s already has field=%s", fs.Type, name)
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *fields) OmitEmpty(e *Encoder, strct reflect.Value) []*field {
|
||||
forced := e.flags&omitEmptyFlag != 0
|
||||
if !fs.hasOmitEmpty && !forced {
|
||||
return fs.List
|
||||
}
|
||||
|
||||
fields := make([]*field, 0, len(fs.List))
|
||||
|
||||
for _, f := range fs.List {
|
||||
if !f.Omit(e, strct) {
|
||||
fields = append(fields, f)
|
||||
}
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func getFields(typ reflect.Type, fallbackTag string) *fields {
|
||||
fs := newFields(typ)
|
||||
|
||||
var omitEmpty bool
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
f := typ.Field(i)
|
||||
|
||||
tagStr := f.Tag.Get(defaultStructTag)
|
||||
if tagStr == "" && fallbackTag != "" {
|
||||
tagStr = f.Tag.Get(fallbackTag)
|
||||
}
|
||||
|
||||
tag := tagparser.Parse(tagStr)
|
||||
if tag.Name == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.Name == "_msgpack" {
|
||||
fs.AsArray = tag.HasOption("as_array") || tag.HasOption("asArray")
|
||||
if tag.HasOption("omitempty") {
|
||||
omitEmpty = true
|
||||
}
|
||||
}
|
||||
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
|
||||
field := &field{
|
||||
name: tag.Name,
|
||||
index: f.Index,
|
||||
omitEmpty: omitEmpty || tag.HasOption("omitempty"),
|
||||
}
|
||||
|
||||
if tag.HasOption("intern") {
|
||||
switch f.Type.Kind() {
|
||||
case reflect.Interface:
|
||||
field.encoder = encodeInternedInterfaceValue
|
||||
field.decoder = decodeInternedInterfaceValue
|
||||
case reflect.String:
|
||||
field.encoder = encodeInternedStringValue
|
||||
field.decoder = decodeInternedStringValue
|
||||
default:
|
||||
err := fmt.Errorf("msgpack: intern strings are not supported on %s", f.Type)
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
field.encoder = getEncoder(f.Type)
|
||||
field.decoder = getDecoder(f.Type)
|
||||
}
|
||||
|
||||
if field.name == "" {
|
||||
field.name = f.Name
|
||||
}
|
||||
|
||||
if f.Anonymous && !tag.HasOption("noinline") {
|
||||
inline := tag.HasOption("inline")
|
||||
if inline {
|
||||
inlineFields(fs, f.Type, field, fallbackTag)
|
||||
} else {
|
||||
inline = shouldInline(fs, f.Type, field, fallbackTag)
|
||||
}
|
||||
|
||||
if inline {
|
||||
if _, ok := fs.Map[field.name]; ok {
|
||||
log.Printf("msgpack: %s already has field=%s", fs.Type, field.name)
|
||||
}
|
||||
fs.Map[field.name] = field
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
fs.Add(field)
|
||||
|
||||
if alias, ok := tag.Options["alias"]; ok {
|
||||
fs.warnIfFieldExists(alias)
|
||||
fs.Map[alias] = field
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
var (
|
||||
encodeStructValuePtr uintptr
|
||||
decodeStructValuePtr uintptr
|
||||
)
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
|
||||
decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
|
||||
}
|
||||
|
||||
func inlineFields(fs *fields, typ reflect.Type, f *field, tag string) {
|
||||
inlinedFields := getFields(typ, tag).List
|
||||
for _, field := range inlinedFields {
|
||||
if _, ok := fs.Map[field.name]; ok {
|
||||
// Don't inline shadowed fields.
|
||||
continue
|
||||
}
|
||||
field.index = append(f.index, field.index...)
|
||||
fs.Add(field)
|
||||
}
|
||||
}
|
||||
|
||||
func shouldInline(fs *fields, typ reflect.Type, f *field, tag string) bool {
|
||||
var encoder encoderFunc
|
||||
var decoder decoderFunc
|
||||
|
||||
if typ.Kind() == reflect.Struct {
|
||||
encoder = f.encoder
|
||||
decoder = f.decoder
|
||||
} else {
|
||||
for typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
encoder = getEncoder(typ)
|
||||
decoder = getDecoder(typ)
|
||||
}
|
||||
if typ.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr {
|
||||
return false
|
||||
}
|
||||
if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr {
|
||||
return false
|
||||
}
|
||||
|
||||
inlinedFields := getFields(typ, tag).List
|
||||
for _, field := range inlinedFields {
|
||||
if _, ok := fs.Map[field.name]; ok {
|
||||
// Don't auto inline if there are shadowed fields.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range inlinedFields {
|
||||
field.index = append(f.index, field.index...)
|
||||
fs.Add(field)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
func (e *Encoder) isEmptyValue(v reflect.Value) bool {
|
||||
kind := v.Kind()
|
||||
|
||||
for kind == reflect.Interface {
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
v = v.Elem()
|
||||
kind = v.Kind()
|
||||
}
|
||||
|
||||
if z, ok := v.Interface().(isZeroer); ok {
|
||||
return nilable(kind) && v.IsNil() || z.IsZero()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Struct:
|
||||
structFields := structs.Fields(v.Type(), e.structTag)
|
||||
fields := structFields.OmitEmpty(e, v)
|
||||
return len(fields) == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Ptr:
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) {
|
||||
if len(index) == 1 {
|
||||
return v.Field(index[0]), true
|
||||
}
|
||||
|
||||
for i, idx := range index {
|
||||
if i > 0 {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return v, false
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
v = v.Field(idx)
|
||||
}
|
||||
|
||||
return v, true
|
||||
}
|
||||
|
||||
func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value {
|
||||
if len(index) == 1 {
|
||||
return v.Field(index[0])
|
||||
}
|
||||
|
||||
for i, idx := range index {
|
||||
if i > 0 {
|
||||
var ok bool
|
||||
v, ok = indirectNil(v)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
v = v.Field(idx)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func indirectNil(v reflect.Value) (reflect.Value, bool) {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
if !v.CanSet() {
|
||||
return v, false
|
||||
}
|
||||
elemType := v.Type().Elem()
|
||||
if elemType.Kind() != reflect.Struct {
|
||||
return v, false
|
||||
}
|
||||
v.Set(cachedValue(elemType))
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
22
vendor/github.com/vmihailenco/msgpack/v5/unsafe.go
generated
vendored
Normal file
22
vendor/github.com/vmihailenco/msgpack/v5/unsafe.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// +build !appengine
|
||||
|
||||
package msgpack
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// bytesToString converts byte slice to string.
|
||||
func bytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// stringToBytes converts string to byte slice.
|
||||
func stringToBytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(
|
||||
&struct {
|
||||
string
|
||||
Cap int
|
||||
}{s, len(s)},
|
||||
))
|
||||
}
|
||||
6
vendor/github.com/vmihailenco/msgpack/v5/version.go
generated
vendored
Normal file
6
vendor/github.com/vmihailenco/msgpack/v5/version.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package msgpack
|
||||
|
||||
// Version is the current release version.
|
||||
func Version() string {
|
||||
return "5.4.1"
|
||||
}
|
||||
19
vendor/github.com/vmihailenco/tagparser/v2/.travis.yml
generated
vendored
Normal file
19
vendor/github.com/vmihailenco/tagparser/v2/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
dist: xenial
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
go_import_path: github.com/vmihailenco/tagparser
|
||||
|
||||
before_install:
|
||||
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1
|
||||
25
vendor/github.com/vmihailenco/tagparser/v2/LICENSE
generated
vendored
Normal file
25
vendor/github.com/vmihailenco/tagparser/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2019 The github.com/vmihailenco/tagparser Authors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
9
vendor/github.com/vmihailenco/tagparser/v2/Makefile
generated
vendored
Normal file
9
vendor/github.com/vmihailenco/tagparser/v2/Makefile
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
all:
|
||||
go test ./...
|
||||
go test ./... -short -race
|
||||
go test ./... -run=NONE -bench=. -benchmem
|
||||
env GOOS=linux GOARCH=386 go test ./...
|
||||
go vet ./...
|
||||
go get github.com/gordonklaus/ineffassign
|
||||
ineffassign .
|
||||
golangci-lint run
|
||||
24
vendor/github.com/vmihailenco/tagparser/v2/README.md
generated
vendored
Normal file
24
vendor/github.com/vmihailenco/tagparser/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Opinionated Golang tag parser
|
||||
|
||||
[](https://travis-ci.org/vmihailenco/tagparser)
|
||||
[](https://godoc.org/github.com/vmihailenco/tagparser)
|
||||
|
||||
## Installation
|
||||
|
||||
Install:
|
||||
|
||||
```shell
|
||||
go get github.com/vmihailenco/tagparser/v2
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
```go
|
||||
func ExampleParse() {
|
||||
tag := tagparser.Parse("some_name,key:value,key2:'complex value'")
|
||||
fmt.Println(tag.Name)
|
||||
fmt.Println(tag.Options)
|
||||
// Output: some_name
|
||||
// map[key:value key2:'complex value']
|
||||
}
|
||||
```
|
||||
82
vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go
generated
vendored
Normal file
82
vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/vmihailenco/tagparser/v2/internal"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
b []byte
|
||||
i int
|
||||
}
|
||||
|
||||
func New(b []byte) *Parser {
|
||||
return &Parser{
|
||||
b: b,
|
||||
}
|
||||
}
|
||||
|
||||
func NewString(s string) *Parser {
|
||||
return New(internal.StringToBytes(s))
|
||||
}
|
||||
|
||||
func (p *Parser) Bytes() []byte {
|
||||
return p.b[p.i:]
|
||||
}
|
||||
|
||||
func (p *Parser) Valid() bool {
|
||||
return p.i < len(p.b)
|
||||
}
|
||||
|
||||
func (p *Parser) Read() byte {
|
||||
if p.Valid() {
|
||||
c := p.b[p.i]
|
||||
p.Advance()
|
||||
return c
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Parser) Peek() byte {
|
||||
if p.Valid() {
|
||||
return p.b[p.i]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Parser) Advance() {
|
||||
p.i++
|
||||
}
|
||||
|
||||
func (p *Parser) Skip(skip byte) bool {
|
||||
if p.Peek() == skip {
|
||||
p.Advance()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Parser) SkipBytes(skip []byte) bool {
|
||||
if len(skip) > len(p.b[p.i:]) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) {
|
||||
return false
|
||||
}
|
||||
p.i += len(skip)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *Parser) ReadSep(sep byte) ([]byte, bool) {
|
||||
ind := bytes.IndexByte(p.b[p.i:], sep)
|
||||
if ind == -1 {
|
||||
b := p.b[p.i:]
|
||||
p.i = len(p.b)
|
||||
return b, false
|
||||
}
|
||||
|
||||
b := p.b[p.i : p.i+ind]
|
||||
p.i += ind + 1
|
||||
return b, true
|
||||
}
|
||||
11
vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go
generated
vendored
Normal file
11
vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// +build appengine
|
||||
|
||||
package internal
|
||||
|
||||
func BytesToString(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func StringToBytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
22
vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go
generated
vendored
Normal file
22
vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// +build !appengine
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BytesToString converts byte slice to string.
|
||||
func BytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// StringToBytes converts string to byte slice.
|
||||
func StringToBytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(
|
||||
&struct {
|
||||
string
|
||||
Cap int
|
||||
}{s, len(s)},
|
||||
))
|
||||
}
|
||||
166
vendor/github.com/vmihailenco/tagparser/v2/tagparser.go
generated
vendored
Normal file
166
vendor/github.com/vmihailenco/tagparser/v2/tagparser.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
package tagparser
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vmihailenco/tagparser/v2/internal/parser"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
Name string
|
||||
Options map[string]string
|
||||
}
|
||||
|
||||
func (t *Tag) HasOption(name string) bool {
|
||||
_, ok := t.Options[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
func Parse(s string) *Tag {
|
||||
p := &tagParser{
|
||||
Parser: parser.NewString(s),
|
||||
}
|
||||
p.parseKey()
|
||||
return &p.Tag
|
||||
}
|
||||
|
||||
type tagParser struct {
|
||||
*parser.Parser
|
||||
|
||||
Tag Tag
|
||||
hasName bool
|
||||
key string
|
||||
}
|
||||
|
||||
func (p *tagParser) setTagOption(key, value string) {
|
||||
key = strings.TrimSpace(key)
|
||||
value = strings.TrimSpace(value)
|
||||
|
||||
if !p.hasName {
|
||||
p.hasName = true
|
||||
if key == "" {
|
||||
p.Tag.Name = value
|
||||
return
|
||||
}
|
||||
}
|
||||
if p.Tag.Options == nil {
|
||||
p.Tag.Options = make(map[string]string)
|
||||
}
|
||||
if key == "" {
|
||||
p.Tag.Options[value] = ""
|
||||
} else {
|
||||
p.Tag.Options[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tagParser) parseKey() {
|
||||
p.key = ""
|
||||
|
||||
var b []byte
|
||||
for p.Valid() {
|
||||
c := p.Read()
|
||||
switch c {
|
||||
case ',':
|
||||
p.Skip(' ')
|
||||
p.setTagOption("", string(b))
|
||||
p.parseKey()
|
||||
return
|
||||
case ':':
|
||||
p.key = string(b)
|
||||
p.parseValue()
|
||||
return
|
||||
case '\'':
|
||||
p.parseQuotedValue()
|
||||
return
|
||||
default:
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
|
||||
if len(b) > 0 {
|
||||
p.setTagOption("", string(b))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tagParser) parseValue() {
|
||||
const quote = '\''
|
||||
c := p.Peek()
|
||||
if c == quote {
|
||||
p.Skip(quote)
|
||||
p.parseQuotedValue()
|
||||
return
|
||||
}
|
||||
|
||||
var b []byte
|
||||
for p.Valid() {
|
||||
c = p.Read()
|
||||
switch c {
|
||||
case '\\':
|
||||
b = append(b, p.Read())
|
||||
case '(':
|
||||
b = append(b, c)
|
||||
b = p.readBrackets(b)
|
||||
case ',':
|
||||
p.Skip(' ')
|
||||
p.setTagOption(p.key, string(b))
|
||||
p.parseKey()
|
||||
return
|
||||
default:
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
p.setTagOption(p.key, string(b))
|
||||
}
|
||||
|
||||
func (p *tagParser) readBrackets(b []byte) []byte {
|
||||
var lvl int
|
||||
loop:
|
||||
for p.Valid() {
|
||||
c := p.Read()
|
||||
switch c {
|
||||
case '\\':
|
||||
b = append(b, p.Read())
|
||||
case '(':
|
||||
b = append(b, c)
|
||||
lvl++
|
||||
case ')':
|
||||
b = append(b, c)
|
||||
lvl--
|
||||
if lvl < 0 {
|
||||
break loop
|
||||
}
|
||||
default:
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *tagParser) parseQuotedValue() {
|
||||
const quote = '\''
|
||||
var b []byte
|
||||
for p.Valid() {
|
||||
bb, ok := p.ReadSep(quote)
|
||||
if !ok {
|
||||
b = append(b, bb...)
|
||||
break
|
||||
}
|
||||
|
||||
// keep the escaped single-quote, and continue until we've found the
|
||||
// one that isn't.
|
||||
if len(bb) > 0 && bb[len(bb)-1] == '\\' {
|
||||
b = append(b, bb[:len(bb)-1]...)
|
||||
b = append(b, quote)
|
||||
continue
|
||||
}
|
||||
|
||||
b = append(b, bb...)
|
||||
break
|
||||
}
|
||||
|
||||
p.setTagOption(p.key, string(b))
|
||||
if p.Skip(',') {
|
||||
p.Skip(' ')
|
||||
}
|
||||
p.parseKey()
|
||||
}
|
||||
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@@ -1202,7 +1202,7 @@ github.com/open-policy-agent/opa/v1/version
|
||||
# github.com/opencloud-eu/libre-graph-api-go v1.0.5
|
||||
## explicit; go 1.18
|
||||
github.com/opencloud-eu/libre-graph-api-go
|
||||
# github.com/opencloud-eu/reva/v2 v2.32.0
|
||||
# github.com/opencloud-eu/reva/v2 v2.32.1-0.20250515093940-2fb4f836b59d
|
||||
## explicit; go 1.24.1
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/runtime
|
||||
@@ -1870,6 +1870,15 @@ github.com/unrolled/secure/cspbuilder
|
||||
# github.com/urfave/cli/v2 v2.27.6
|
||||
## explicit; go 1.18
|
||||
github.com/urfave/cli/v2
|
||||
# github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
## explicit; go 1.19
|
||||
github.com/vmihailenco/msgpack/v5
|
||||
github.com/vmihailenco/msgpack/v5/msgpcode
|
||||
# github.com/vmihailenco/tagparser/v2 v2.0.0
|
||||
## explicit; go 1.15
|
||||
github.com/vmihailenco/tagparser/v2
|
||||
github.com/vmihailenco/tagparser/v2/internal
|
||||
github.com/vmihailenco/tagparser/v2/internal/parser
|
||||
# github.com/wk8/go-ordered-map v1.0.0
|
||||
## explicit; go 1.14
|
||||
github.com/wk8/go-ordered-map
|
||||
@@ -2168,7 +2177,7 @@ golang.org/x/image/vector
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/module
|
||||
golang.org/x/mod/semver
|
||||
# golang.org/x/net v0.40.0
|
||||
# golang.org/x/net v0.39.0
|
||||
## explicit; go 1.23.0
|
||||
golang.org/x/net/bpf
|
||||
golang.org/x/net/context
|
||||
|
||||
Reference in New Issue
Block a user