slidge-whatsapp 0.2.7__cp312-cp312-manylinux_2_36_aarch64.whl → 0.3.0__cp312-cp312-manylinux_2_36_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of slidge-whatsapp might be problematic. Click here for more details.
- slidge_whatsapp/contact.py +15 -3
- slidge_whatsapp/event.go +144 -48
- slidge_whatsapp/gateway.go +7 -63
- slidge_whatsapp/gateway.py +2 -3
- slidge_whatsapp/generated/_whatsapp.cpython-312-aarch64-linux-gnu.h +146 -129
- slidge_whatsapp/generated/_whatsapp.cpython-312-aarch64-linux-gnu.so +0 -0
- slidge_whatsapp/generated/build.py +114 -100
- slidge_whatsapp/generated/whatsapp.c +1309 -1037
- slidge_whatsapp/generated/whatsapp.go +779 -668
- slidge_whatsapp/generated/whatsapp.py +1168 -1043
- slidge_whatsapp/generated/whatsapp_go.h +146 -129
- slidge_whatsapp/go.mod +18 -15
- slidge_whatsapp/go.sum +38 -26
- slidge_whatsapp/group.py +34 -30
- slidge_whatsapp/media/media.go +1 -1
- slidge_whatsapp/session.go +34 -17
- slidge_whatsapp/session.py +46 -14
- slidge_whatsapp/vendor/github.com/beeper/argo-go/LICENSE +9 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/block/blockreader.go +329 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/block/blockwriter.go +417 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/codec/decoder.go +652 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/codec/encoder.go +985 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/header/header.go +135 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/internal/util/util.go +133 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/label/label.go +384 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/label/wiremarkers.go +37 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/pkg/bitset/bitset.go +197 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/pkg/buf/buf.go +420 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/pkg/varint/varint.go +246 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/wire/wire.go +614 -0
- slidge_whatsapp/vendor/github.com/beeper/argo-go/wirecodec/decode.go +341 -0
- slidge_whatsapp/vendor/github.com/elliotchance/orderedmap/v3/LICENSE +21 -0
- slidge_whatsapp/vendor/github.com/elliotchance/orderedmap/v3/list.go +95 -0
- slidge_whatsapp/vendor/github.com/elliotchance/orderedmap/v3/orderedmap.go +187 -0
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/fitz.go +1 -0
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/fitz_cgo.go +3 -0
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/fitz_nocgo.go +4 -5
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/purego_darwin.go +11 -1
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/purego_linux.go +10 -0
- slidge_whatsapp/vendor/github.com/gen2brain/go-fitz/purego_windows.go +12 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/.gitignore +0 -2
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/CHANGELOG.md +30 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/COPYRIGHT.txt +6 -1
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/README.md +14 -17
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/abi.go +1 -1
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/abi2.go +7 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/assets/libffi/LICENSE +21 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/assets/libffi/darwin_amd64/libffi.8.dylib +0 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/assets/libffi/darwin_arm64/libffi.8.dylib +0 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/assets/libffi/windows_amd64/libffi-8.dll +0 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/cif.go +15 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/cif_arm64.go +16 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/embed.go +49 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/embed_darwin_amd64.go +10 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/embed_darwin_arm64.go +10 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/embed_windows_amd64.go +10 -0
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/ffi.go +51 -13
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/init.go +22 -9
- slidge_whatsapp/vendor/github.com/mattn/go-sqlite3/README.md +2 -0
- slidge_whatsapp/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c +3096 -1651
- slidge_whatsapp/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h +188 -128
- slidge_whatsapp/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_userauth.go +13 -140
- slidge_whatsapp/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h +4 -0
- slidge_whatsapp/vendor/github.com/petermattis/goid/runtime_go1.23.go +2 -2
- slidge_whatsapp/vendor/github.com/petermattis/goid/runtime_go1.25.go +37 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/LICENSE +19 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/argmap.go +37 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/collections.go +148 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/comment.go +31 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/decode.go +216 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/definition.go +110 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/directive.go +43 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/document.go +89 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go +159 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/fragment.go +41 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/operation.go +32 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/path.go +72 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/selection.go +41 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/source.go +19 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/type.go +68 -0
- slidge_whatsapp/vendor/github.com/vektah/gqlparser/v2/ast/value.go +122 -0
- slidge_whatsapp/vendor/go.mau.fi/util/exhttp/handleerrors.go +60 -26
- slidge_whatsapp/vendor/go.mau.fi/util/exhttp/networkerror.go +2 -1
- slidge_whatsapp/vendor/go.mau.fi/util/exstrings/stringutil.go +28 -0
- slidge_whatsapp/vendor/go.mau.fi/util/exsync/event.go +19 -3
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/.pre-commit-config.yaml +3 -3
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate/decode.go +1 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate/hash.go +1 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate.go +5 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/argo/argo-wire-type-store.argo +63 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/argo/argo.go +62 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/argo/name-to-queryids.json +306 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/armadillomessage.go +3 -2
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/call.go +1 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/client.go +15 -18
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/connectionevents.go +5 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/download.go +4 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/errors.go +3 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/group.go +97 -25
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/internals.go +22 -10
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/message.go +10 -9
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/msgsecret.go +2 -14
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/newsletter.go +83 -7
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/notification.go +5 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/pair-code.go +2 -2
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/presence.go +15 -6
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waBotMetadata/WABotMetadata.pb.go +5156 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waBotMetadata/WABotMetadata.proto +516 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waCompanionReg/WACompanionReg.pb.go +30 -3
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waCompanionReg/WACompanionReg.proto +3 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.pb.go +8532 -11526
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.proto +132 -438
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waHistorySync/WAWebProtobufsHistorySync.pb.go +52 -23
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waHistorySync/WAWebProtobufsHistorySync.proto +3 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.pb.go +225 -73
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.proto +21 -5
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.pb.go +884 -441
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.proto +40 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWa6/WAWebProtobufsWa6.pb.go +60 -38
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWa6/WAWebProtobufsWa6.proto +3 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/receipt.go +8 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/send.go +6 -4
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/clientpayload.go +1 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/noop.go +3 -2
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go +25 -5
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/store.go +3 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/call.go +1 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/events/events.go +8 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/jid.go +2 -1
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/user.go +2 -0
- slidge_whatsapp/vendor/go.mau.fi/whatsmeow/user.go +12 -8
- slidge_whatsapp/vendor/golang.org/x/crypto/curve25519/curve25519.go +1 -1
- slidge_whatsapp/vendor/golang.org/x/net/http2/config.go +44 -2
- slidge_whatsapp/vendor/golang.org/x/net/http2/gotrack.go +14 -3
- slidge_whatsapp/vendor/golang.org/x/net/http2/http2.go +7 -29
- slidge_whatsapp/vendor/golang.org/x/net/http2/server.go +53 -71
- slidge_whatsapp/vendor/golang.org/x/net/http2/transport.go +20 -74
- slidge_whatsapp/vendor/golang.org/x/sys/unix/affinity_linux.go +1 -3
- slidge_whatsapp/vendor/golang.org/x/sys/unix/mkerrors.sh +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/syscall_darwin.go +1 -55
- slidge_whatsapp/vendor/golang.org/x/sys/unix/syscall_solaris.go +1 -1
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux.go +47 -16
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +3 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +4 -4
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +1 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux.go +168 -12
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +17 -1
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +18 -2
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +17 -1
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +17 -1
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +18 -2
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +16 -0
- slidge_whatsapp/vendor/golang.org/x/sys/windows/types_windows.go +6 -0
- slidge_whatsapp/vendor/golang.org/x/sys/windows/zsyscall_windows.go +483 -483
- slidge_whatsapp/vendor/google.golang.org/protobuf/encoding/protowire/wire.go +25 -1
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb +0 -0
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/filedesc/editions.go +10 -5
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/filedesc/presence.go +33 -0
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/genid/api_gen.go +6 -0
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go +68 -22
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/impl/codec_message_opaque.go +2 -1
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/impl/message_opaque.go +8 -37
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/impl/presence.go +0 -3
- slidge_whatsapp/vendor/google.golang.org/protobuf/internal/version/version.go +1 -1
- slidge_whatsapp/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go +8 -0
- slidge_whatsapp/vendor/modules.txt +43 -23
- {slidge_whatsapp-0.2.7.dist-info → slidge_whatsapp-0.3.0.dist-info}/METADATA +5 -4
- {slidge_whatsapp-0.2.7.dist-info → slidge_whatsapp-0.3.0.dist-info}/RECORD +208 -161
- {slidge_whatsapp-0.2.7.dist-info → slidge_whatsapp-0.3.0.dist-info}/WHEEL +1 -1
- slidge_whatsapp/vendor/github.com/jupiterrider/ffi/abi_amd64.go +0 -7
- slidge_whatsapp/vendor/golang.org/x/net/http2/config_go124.go +0 -61
- slidge_whatsapp/vendor/golang.org/x/net/http2/config_pre_go124.go +0 -16
- slidge_whatsapp/vendor/golang.org/x/net/http2/timer.go +0 -20
- {slidge_whatsapp-0.2.7.dist-info → slidge_whatsapp-0.3.0.dist-info}/entry_points.txt +0 -0
- {slidge_whatsapp-0.2.7.dist-info → slidge_whatsapp-0.3.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
// Package codec provides the tools for encoding and decoding Argo data.
|
|
2
|
+
// This file focuses on the ArgoDecoder, which is responsible for parsing
|
|
3
|
+
// Argo binary messages and reconstructing them into Go data structures,
|
|
4
|
+
// typically an ordered map representing a GraphQL ExecutionResult.
|
|
5
|
+
package codec
|
|
6
|
+
|
|
7
|
+
import (
|
|
8
|
+
"encoding/binary"
|
|
9
|
+
"fmt"
|
|
10
|
+
"io"
|
|
11
|
+
"math"
|
|
12
|
+
"strconv"
|
|
13
|
+
|
|
14
|
+
"github.com/elliotchance/orderedmap/v3"
|
|
15
|
+
"github.com/vektah/gqlparser/v2/ast"
|
|
16
|
+
|
|
17
|
+
"github.com/beeper/argo-go/block"
|
|
18
|
+
"github.com/beeper/argo-go/header"
|
|
19
|
+
"github.com/beeper/argo-go/internal/util"
|
|
20
|
+
"github.com/beeper/argo-go/label"
|
|
21
|
+
"github.com/beeper/argo-go/pkg/buf"
|
|
22
|
+
"github.com/beeper/argo-go/wire"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// anyBlockReader defines an interface for a generic block reader.
|
|
26
|
+
// Implementations of this interface are responsible for reading a specific
|
|
27
|
+
// type of data (e.g., string, varint) from a block within an Argo message.
|
|
28
|
+
// The Read method takes the parent buffer (which might be the core message buffer
|
|
29
|
+
// or a buffer for a specific record/array context) and returns the decoded data
|
|
30
|
+
// as an interface{} value, along with any error encountered.
|
|
31
|
+
type anyBlockReader interface {
|
|
32
|
+
Read(parentBuf buf.Read) (interface{}, error)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// argoError represents a structured error encountered during Argo decoding.
|
|
36
|
+
// It includes the path within the data structure where the error occurred,
|
|
37
|
+
// a descriptive message, and the byte position in the input buffer.
|
|
38
|
+
type argoError struct {
|
|
39
|
+
Path ast.Path
|
|
40
|
+
Msg string
|
|
41
|
+
Pos int64
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Error implements the error interface for argoError.
|
|
45
|
+
func (e *argoError) Error() string {
|
|
46
|
+
return fmt.Sprintf("Argo decoding error at path %s (pos %d): %s", util.FormatPath(e.Path), e.Pos, e.Msg)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// newArgoError creates a new argoError with the given path, position, and formatted message.
|
|
50
|
+
func newArgoError(path ast.Path, pos int64, format string, args ...interface{}) error {
|
|
51
|
+
return &argoError{Path: path, Pos: pos, Msg: fmt.Errorf(format, args...).Error()}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ArgoDecoder decodes an Argo binary message into a Go data structure.
|
|
55
|
+
// It uses a MessageSlicer to access different parts of the Argo message (header, blocks, core)
|
|
56
|
+
// and maintains a map of block readers to efficiently decode block data.
|
|
57
|
+
type ArgoDecoder struct {
|
|
58
|
+
slicer *MessageSlicer
|
|
59
|
+
readers map[wire.BlockKey]anyBlockReader // Caches block readers by their key.
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// NewArgoDecoder creates and initializes a new ArgoDecoder.
|
|
63
|
+
// messageBuf should contain the entire Argo message to be decoded.
|
|
64
|
+
// It returns an error if the message slicer cannot be initialized (e.g., due to header read issues).
|
|
65
|
+
func NewArgoDecoder(messageBuf buf.Read) (*ArgoDecoder, error) {
|
|
66
|
+
slicer, err := NewMessageSlicer(messageBuf)
|
|
67
|
+
if err != nil {
|
|
68
|
+
return nil, fmt.Errorf("failed to initialize message slicer: %w", err)
|
|
69
|
+
}
|
|
70
|
+
return &ArgoDecoder{
|
|
71
|
+
slicer: slicer,
|
|
72
|
+
readers: make(map[wire.BlockKey]anyBlockReader),
|
|
73
|
+
}, nil
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ArgoToMap decodes the entire Argo message into an ordered map, which typically
|
|
77
|
+
// represents a GraphQL ExecutionResult. The wire.Type `wt` specifies the expected
|
|
78
|
+
// structure of the data. If the Argo message header indicates it is self-describing,
|
|
79
|
+
// the provided `wt` is overridden by `wire.Desc`.
|
|
80
|
+
func (ad *ArgoDecoder) ArgoToMap(wt wire.Type) (*orderedmap.OrderedMap[string, interface{}], error) {
|
|
81
|
+
finalWt := wt
|
|
82
|
+
|
|
83
|
+
if _, wantDesc := wt.(wire.DescType); wantDesc && ad.slicer.Header().GetFlag(header.HeaderSelfDescribingFlag) {
|
|
84
|
+
finalWt = wire.Desc
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if p, ok := ad.slicer.Core().(buf.BufPosition); ok {
|
|
88
|
+
p.SetPosition(0)
|
|
89
|
+
}
|
|
90
|
+
result, err := ad.readArgo(ad.slicer.Core(), nil, finalWt, nil)
|
|
91
|
+
if err != nil {
|
|
92
|
+
return nil, err
|
|
93
|
+
}
|
|
94
|
+
if m, ok := result.(*orderedmap.OrderedMap[string, interface{}]); ok {
|
|
95
|
+
return m, nil
|
|
96
|
+
}
|
|
97
|
+
return nil, fmt.Errorf("decoded result is not an ordered map, got %T", result)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
func (ad *ArgoDecoder) readArgo(b buf.Read, currentPath ast.Path, wt wire.Type, currentBlock *wire.BlockType) (interface{}, error) {
|
|
101
|
+
switch typedWt := wt.(type) {
|
|
102
|
+
case wire.BlockType:
|
|
103
|
+
trackVal := orderedmap.NewOrderedMap[string, interface{}]()
|
|
104
|
+
trackVal.Set("key", typedWt.Key)
|
|
105
|
+
trackVal.Set("dedupe", typedWt.Dedupe)
|
|
106
|
+
return ad.readArgo(b, currentPath, typedWt.Of, &typedWt)
|
|
107
|
+
|
|
108
|
+
case wire.NullableType:
|
|
109
|
+
peekBytes, err := b.Peek(1)
|
|
110
|
+
if err != nil {
|
|
111
|
+
if err == io.EOF { // EOF here means the buffer ended before a nullable marker could be read.
|
|
112
|
+
return nil, newArgoError(currentPath, b.Position(), "unexpected EOF while peeking for nullable type marker")
|
|
113
|
+
}
|
|
114
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to peek for nullable type marker: %w", err)
|
|
115
|
+
}
|
|
116
|
+
peekLabelByte := peekBytes[0]
|
|
117
|
+
|
|
118
|
+
if peekLabelByte == label.Null[0] { // Compare the first byte of the pre-encoded Null label.
|
|
119
|
+
_, _ = b.ReadByte() // Consume the null label byte.
|
|
120
|
+
return nil, nil
|
|
121
|
+
}
|
|
122
|
+
if peekLabelByte == label.Absent[0] { // Compare the first byte of the pre-encoded Absent label.
|
|
123
|
+
_, _ = b.ReadByte() // Consume the absent label byte.
|
|
124
|
+
return wire.AbsentValue, nil // Return a special marker for absent, to be handled by RECORD logic.
|
|
125
|
+
}
|
|
126
|
+
if peekLabelByte == label.Error[0] { // Compare the first byte of the pre-encoded Error label.
|
|
127
|
+
_, _ = b.ReadByte() // Consume the error label byte.
|
|
128
|
+
|
|
129
|
+
lengthLabel, err := label.Read(b)
|
|
130
|
+
if err != nil {
|
|
131
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read error array length: %w", err)
|
|
132
|
+
}
|
|
133
|
+
length := int(lengthLabel.Value().Int64())
|
|
134
|
+
if length < 0 {
|
|
135
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid negative error array length: %d", length)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Argo Spec: Field errors propagate to the nearest nullable field.
|
|
139
|
+
// The errors are then written. The `path` field in these errors is relative.
|
|
140
|
+
// "implementations should make full path easily available to users."
|
|
141
|
+
// The spec also says: "return null // simple for compatibility, but up to implementations what to do with inline errors"
|
|
142
|
+
// We collect the errors and then return nil for the field value itself, as per spec.
|
|
143
|
+
// The collected `errors` are not directly returned by this function but could be logged
|
|
144
|
+
// or otherwise handled by the calling application if needed.
|
|
145
|
+
errors := make([]interface{}, length)
|
|
146
|
+
for i := 0; i < length; i++ {
|
|
147
|
+
var errItem interface{}
|
|
148
|
+
errPath := util.AddPathIndex(currentPath, i)
|
|
149
|
+
if ad.slicer.Header().GetFlag(header.HeaderSelfDescribingErrorsFlag) {
|
|
150
|
+
errItem, err = ad.readSelfDescribing(b, errPath)
|
|
151
|
+
} else {
|
|
152
|
+
errItem, err = ad.readArgo(b, errPath, wire.Error, nil) // currentBlock is nil for Error type
|
|
153
|
+
}
|
|
154
|
+
if err != nil {
|
|
155
|
+
return nil, newArgoError(errPath, b.Position(), "failed to read error item %d: %w", i, err)
|
|
156
|
+
}
|
|
157
|
+
errors[i] = errItem
|
|
158
|
+
}
|
|
159
|
+
// The value of the field is null when there's an inline error.
|
|
160
|
+
// The collected `errors` array here is for potential side-channel processing (e.g. logging)
|
|
161
|
+
// but is not part of the main decoded result for this field.
|
|
162
|
+
return nil, nil
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if !wire.IsLabeled(typedWt.Of) {
|
|
166
|
+
// For non-labeled types within a Nullable, expect a NonNullMarker (value 0) if not null/absent/error.
|
|
167
|
+
marker, err := label.Read(b)
|
|
168
|
+
if err != nil {
|
|
169
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read non-null marker: %w", err)
|
|
170
|
+
}
|
|
171
|
+
if !label.NonNullMarker.Is(marker) {
|
|
172
|
+
return nil, newArgoError(currentPath, b.Position(),
|
|
173
|
+
"invalid non-null marker %s for %s. Path: %s, Pos: %d",
|
|
174
|
+
marker.Value().String(), wire.Print(wt), util.FormatPath(currentPath), b.Position())
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// If labeled, no non-null marker is read here; the underlying type's label reading handles it.
|
|
178
|
+
// Proceed to read the actual underlying type.
|
|
179
|
+
return ad.readArgo(b, currentPath, typedWt.Of, currentBlock)
|
|
180
|
+
|
|
181
|
+
case wire.RecordType:
|
|
182
|
+
obj := orderedmap.NewOrderedMapWithCapacity[string, interface{}](len(typedWt.Fields))
|
|
183
|
+
|
|
184
|
+
for _, field := range typedWt.Fields {
|
|
185
|
+
fieldPath := util.AddPathName(currentPath, field.Name)
|
|
186
|
+
|
|
187
|
+
var fieldValue interface{}
|
|
188
|
+
var err error
|
|
189
|
+
|
|
190
|
+
if field.Omittable {
|
|
191
|
+
peekBytes, errPeek := b.Peek(1)
|
|
192
|
+
if errPeek != nil {
|
|
193
|
+
return nil, newArgoError(fieldPath, b.Position(), "failed to peek for omittable field %s: %w", field.Name, errPeek)
|
|
194
|
+
}
|
|
195
|
+
labelPeekByte := peekBytes[0]
|
|
196
|
+
|
|
197
|
+
// Regarding Error labels for omittable fields:
|
|
198
|
+
// The Argo spec states: "Nullable fields are the only valid location for Field errors".
|
|
199
|
+
// If field.Of is Nullable, the wire.NullableType case in this function will handle any Error labels.
|
|
200
|
+
// If field.Of is not Nullable, an Error label should not appear here according to the spec.
|
|
201
|
+
// The reference JS implementation's check for `labelPeek == Label.Error[0]` in this context
|
|
202
|
+
// might be for a slightly different interpretation or an older version of the spec.
|
|
203
|
+
// This Go implementation adheres to "Error labels only on Nullable".
|
|
204
|
+
|
|
205
|
+
if !wire.IsLabeled(field.Of) && labelPeekByte == label.NonNull[0] {
|
|
206
|
+
_, _ = b.ReadByte() // Consume non-null marker.
|
|
207
|
+
fieldValue, err = ad.readArgo(b, fieldPath, field.Of, currentBlock)
|
|
208
|
+
} else if labelPeekByte == label.Absent[0] {
|
|
209
|
+
_, _ = b.ReadByte() // Consume absent marker.
|
|
210
|
+
fieldValue = wire.AbsentValue
|
|
211
|
+
} else {
|
|
212
|
+
// Neither NonNull (for unlabeled types) nor Absent.
|
|
213
|
+
// Proceed to read normally:
|
|
214
|
+
// - If field.Of is labeled, its own label will be read by the recursive call.
|
|
215
|
+
// - If field.Of is unlabeled (and we didn't see a NonNull marker), it's a direct value.
|
|
216
|
+
fieldValue, err = ad.readArgo(b, fieldPath, field.Of, currentBlock)
|
|
217
|
+
}
|
|
218
|
+
} else { // Not omittable.
|
|
219
|
+
fieldValue, err = ad.readArgo(b, fieldPath, field.Of, currentBlock)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if err != nil {
|
|
223
|
+
return nil, err // Error already contextualized by recursive call
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if fieldValue != wire.AbsentValue {
|
|
227
|
+
obj.Set(field.Name, fieldValue)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return obj, nil
|
|
231
|
+
|
|
232
|
+
case wire.ArrayType:
|
|
233
|
+
lengthLabel, err := label.Read(b)
|
|
234
|
+
if err != nil {
|
|
235
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read array length: %w", err)
|
|
236
|
+
}
|
|
237
|
+
length := int(lengthLabel.Value().Int64())
|
|
238
|
+
if length < 0 {
|
|
239
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid negative array length: %d", length)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
arr := make([]interface{}, length) // This is a slice, not a map.
|
|
243
|
+
for i := 0; i < length; i++ {
|
|
244
|
+
itemPath := util.AddPathIndex(currentPath, i)
|
|
245
|
+
item, err := ad.readArgo(b, itemPath, typedWt.Of, currentBlock)
|
|
246
|
+
if err != nil {
|
|
247
|
+
return nil, newArgoError(itemPath, b.Position(), "failed to read array item %d: %w", i, err)
|
|
248
|
+
}
|
|
249
|
+
if item == wire.AbsentValue {
|
|
250
|
+
// JSON arrays don't have "absent" elements, they'd be null.
|
|
251
|
+
// For now, treat absent as null in an array.
|
|
252
|
+
arr[i] = nil
|
|
253
|
+
} else {
|
|
254
|
+
arr[i] = item
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return arr, nil
|
|
258
|
+
|
|
259
|
+
case wire.BooleanType:
|
|
260
|
+
l, err := label.Read(b)
|
|
261
|
+
if err != nil {
|
|
262
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read boolean label: %w", err)
|
|
263
|
+
}
|
|
264
|
+
if label.FalseMarker.Is(l) {
|
|
265
|
+
return false, nil
|
|
266
|
+
}
|
|
267
|
+
if label.TrueMarker.Is(l) {
|
|
268
|
+
return true, nil
|
|
269
|
+
}
|
|
270
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid boolean label %s", l.Value().String())
|
|
271
|
+
|
|
272
|
+
case wire.StringType, wire.BytesType, wire.VarintType, wire.Float64Type, wire.FixedType:
|
|
273
|
+
if currentBlock == nil {
|
|
274
|
+
return nil, newArgoError(currentPath, b.Position(), "programmer error: need block for %s", wire.Print(wt))
|
|
275
|
+
}
|
|
276
|
+
reader, err := ad.getBlockReader(*currentBlock, wt)
|
|
277
|
+
if err != nil {
|
|
278
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to get block reader for %s (key %s): %w", wire.Print(wt), currentBlock.Key, err)
|
|
279
|
+
}
|
|
280
|
+
value, err := reader.Read(b) // `b` is the parent buffer (core or record/array context)
|
|
281
|
+
if err != nil {
|
|
282
|
+
return nil, newArgoError(currentPath, b.Position(), "block reader failed for %s (key %s): %w", wire.Print(wt), currentBlock.Key, err)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return value, nil
|
|
286
|
+
|
|
287
|
+
case wire.DescType:
|
|
288
|
+
return ad.readSelfDescribing(b, currentPath)
|
|
289
|
+
|
|
290
|
+
case wire.PathType: // Path type is usually part of Error structure.
|
|
291
|
+
// Decoding a raw PATH here would mean reading an ARRAY of VARINT.
|
|
292
|
+
// This is essentially ArrayType{Of: Varint}
|
|
293
|
+
return ad.readArgo(b, currentPath, wire.ArrayType{Of: wire.Varint}, currentBlock)
|
|
294
|
+
|
|
295
|
+
default:
|
|
296
|
+
return nil, newArgoError(currentPath, b.Position(), "unsupported wire type %T: %s", wt, wire.Print(wt))
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
func (ad *ArgoDecoder) readSelfDescribing(b buf.Read, currentPath ast.Path) (interface{}, error) {
|
|
301
|
+
typeMarkerLabel, err := label.Read(b)
|
|
302
|
+
if err != nil {
|
|
303
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read self-describing type marker: %w", err)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
switch {
|
|
307
|
+
case wire.SelfDescribingTypeMarkerNull.Is(typeMarkerLabel):
|
|
308
|
+
return nil, nil
|
|
309
|
+
case wire.SelfDescribingTypeMarkerFalse.Is(typeMarkerLabel):
|
|
310
|
+
return false, nil
|
|
311
|
+
case wire.SelfDescribingTypeMarkerTrue.Is(typeMarkerLabel):
|
|
312
|
+
return true, nil
|
|
313
|
+
case wire.SelfDescribingTypeMarkerObject.Is(typeMarkerLabel):
|
|
314
|
+
lengthLabel, err := label.Read(b)
|
|
315
|
+
if err != nil {
|
|
316
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read self-describing object length: %w", err)
|
|
317
|
+
}
|
|
318
|
+
length := int(lengthLabel.Value().Int64())
|
|
319
|
+
if length < 0 {
|
|
320
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid negative self-describing object length: %d", length)
|
|
321
|
+
}
|
|
322
|
+
obj := orderedmap.NewOrderedMapWithCapacity[string, interface{}](length)
|
|
323
|
+
|
|
324
|
+
for i := 0; i < length; i++ {
|
|
325
|
+
// Field name is a string, using the self-describing string block
|
|
326
|
+
fieldNamePath := util.AddPathName(currentPath, strconv.Itoa(i)+"_key") // Path for the key itself
|
|
327
|
+
|
|
328
|
+
// Construct the String BlockType for self-describing field names
|
|
329
|
+
stringBlockKey := wire.BlockKey("String")
|
|
330
|
+
stringElementType, ok := wire.SelfDescribingBlocks[stringBlockKey]
|
|
331
|
+
if !ok {
|
|
332
|
+
return nil, newArgoError(fieldNamePath, b.Position(), "self-describing string block key not found in map")
|
|
333
|
+
}
|
|
334
|
+
selfDescribingStringBlock := wire.NewBlockType(stringElementType, stringBlockKey, wire.MustDeduplicateByDefault(stringElementType))
|
|
335
|
+
|
|
336
|
+
fieldNameVal, err := ad.readArgo(b, fieldNamePath, wire.String, &selfDescribingStringBlock)
|
|
337
|
+
if err != nil {
|
|
338
|
+
return nil, newArgoError(fieldNamePath, b.Position(), "failed to read self-describing object field name %d: %w", i, err)
|
|
339
|
+
}
|
|
340
|
+
fieldName, ok := fieldNameVal.(string)
|
|
341
|
+
if !ok {
|
|
342
|
+
return nil, newArgoError(fieldNamePath, b.Position(), "self-describing object field name %d is not a string", i)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Field value is recursively self-describing
|
|
346
|
+
fieldValuePath := util.AddPathName(currentPath, fieldName) // Path for the value
|
|
347
|
+
value, err := ad.readSelfDescribing(b, fieldValuePath)
|
|
348
|
+
if err != nil {
|
|
349
|
+
return nil, newArgoError(fieldValuePath, b.Position(), "failed to read self-describing object field value for '%s': %w", fieldName, err)
|
|
350
|
+
}
|
|
351
|
+
obj.Set(fieldName, value)
|
|
352
|
+
}
|
|
353
|
+
return obj, nil
|
|
354
|
+
|
|
355
|
+
case wire.SelfDescribingTypeMarkerList.Is(typeMarkerLabel):
|
|
356
|
+
lengthLabel, err := label.Read(b)
|
|
357
|
+
if err != nil {
|
|
358
|
+
return nil, newArgoError(currentPath, b.Position(), "failed to read self-describing list length: %w", err)
|
|
359
|
+
}
|
|
360
|
+
length := int(lengthLabel.Value().Int64())
|
|
361
|
+
if length < 0 {
|
|
362
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid negative self-describing list length: %d", length)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
list := make([]interface{}, length) // This is a slice, not a map.
|
|
366
|
+
for i := 0; i < length; i++ {
|
|
367
|
+
itemPath := util.AddPathIndex(currentPath, i)
|
|
368
|
+
item, err := ad.readSelfDescribing(b, itemPath)
|
|
369
|
+
if err != nil {
|
|
370
|
+
return nil, newArgoError(itemPath, b.Position(), "failed to read self-describing list item %d: %w", i, err)
|
|
371
|
+
}
|
|
372
|
+
list[i] = item
|
|
373
|
+
}
|
|
374
|
+
return list, nil
|
|
375
|
+
|
|
376
|
+
case wire.SelfDescribingTypeMarkerString.Is(typeMarkerLabel):
|
|
377
|
+
stringBlockKey := wire.BlockKey("String")
|
|
378
|
+
stringElementType, ok := wire.SelfDescribingBlocks[stringBlockKey]
|
|
379
|
+
if !ok {
|
|
380
|
+
return nil, newArgoError(currentPath, b.Position(), "self-describing string block key not found in map")
|
|
381
|
+
}
|
|
382
|
+
selfDescribingStringBlock := wire.NewBlockType(stringElementType, stringBlockKey, wire.MustDeduplicateByDefault(stringElementType))
|
|
383
|
+
return ad.readArgo(b, currentPath, wire.String, &selfDescribingStringBlock)
|
|
384
|
+
case wire.SelfDescribingTypeMarkerBytes.Is(typeMarkerLabel):
|
|
385
|
+
bytesBlockKey := wire.BlockKey("Bytes")
|
|
386
|
+
bytesElementType, ok := wire.SelfDescribingBlocks[bytesBlockKey]
|
|
387
|
+
if !ok {
|
|
388
|
+
return nil, newArgoError(currentPath, b.Position(), "self-describing bytes block key not found in map")
|
|
389
|
+
}
|
|
390
|
+
selfDescribingBytesBlock := wire.NewBlockType(bytesElementType, bytesBlockKey, wire.MustDeduplicateByDefault(bytesElementType))
|
|
391
|
+
return ad.readArgo(b, currentPath, wire.Bytes, &selfDescribingBytesBlock)
|
|
392
|
+
case wire.SelfDescribingTypeMarkerInt.Is(typeMarkerLabel):
|
|
393
|
+
varintBlockKey := wire.BlockKey("Int") // As defined in wire/wire.go init for VarintBlock
|
|
394
|
+
varintElementType, ok := wire.SelfDescribingBlocks[varintBlockKey]
|
|
395
|
+
if !ok {
|
|
396
|
+
return nil, newArgoError(currentPath, b.Position(), "self-describing varint block key ('Int') not found in map")
|
|
397
|
+
}
|
|
398
|
+
selfDescribingVarintBlock := wire.NewBlockType(varintElementType, varintBlockKey, wire.MustDeduplicateByDefault(varintElementType))
|
|
399
|
+
return ad.readArgo(b, currentPath, wire.Varint, &selfDescribingVarintBlock)
|
|
400
|
+
case wire.SelfDescribingTypeMarkerFloat.Is(typeMarkerLabel):
|
|
401
|
+
// The reference JS implementation uses "Float" as the key for self-describing float blocks.
|
|
402
|
+
// Ensure wire.SelfDescribingBlocks is populated with this key if this path is taken.
|
|
403
|
+
// Currently, wire.go's init for SelfDescribingBlocks does not include a "Float" block.
|
|
404
|
+
// This might indicate a mismatch or an untested path.
|
|
405
|
+
// For now, we assume "Float" is the intended key.
|
|
406
|
+
floatBlockKey := wire.BlockKey("Float")
|
|
407
|
+
floatElementType, ok := wire.SelfDescribingBlocks[floatBlockKey]
|
|
408
|
+
if !ok {
|
|
409
|
+
// Let's add a more specific error, and check wire.go's SelfDescribingBlocks initialization.
|
|
410
|
+
return nil, newArgoError(currentPath, b.Position(), "self-describing float block key ('Float') not found in wire.SelfDescribingBlocks map. Check wire.go.")
|
|
411
|
+
}
|
|
412
|
+
selfDescribingFloatBlock := wire.NewBlockType(floatElementType, floatBlockKey, wire.MustDeduplicateByDefault(floatElementType))
|
|
413
|
+
return ad.readArgo(b, currentPath, wire.Float64, &selfDescribingFloatBlock)
|
|
414
|
+
default:
|
|
415
|
+
return nil, newArgoError(currentPath, b.Position(), "invalid self-describing type marker: %s", typeMarkerLabel.Value().String())
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// getBlockReader retrieves or creates and caches a block reader for a given block definition.
|
|
420
|
+
func (ad *ArgoDecoder) getBlockReader(blockDef wire.BlockType, valueWireType wire.Type) (anyBlockReader, error) {
|
|
421
|
+
if reader, found := ad.readers[blockDef.Key]; found {
|
|
422
|
+
return reader, nil
|
|
423
|
+
}
|
|
424
|
+
reader, err := ad.makeBlockReader(valueWireType, blockDef.Dedupe, blockDef.Key)
|
|
425
|
+
if err != nil {
|
|
426
|
+
return nil, err
|
|
427
|
+
}
|
|
428
|
+
ad.readers[blockDef.Key] = reader
|
|
429
|
+
return reader, nil
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// and handles type-specific post-processing.
|
|
433
|
+
type genericBlockReaderWrapper struct {
|
|
434
|
+
// coreRead is the underlying block-specific read function.
|
|
435
|
+
// It's typically a method from a block.Reader implementation (e.g., block.LabelBlockReader.Read).
|
|
436
|
+
coreRead func(parentBuf buf.Read) (interface{}, error)
|
|
437
|
+
// blockDataBuffer is the buffer specific to this block's data.
|
|
438
|
+
// It's used by some block readers that need to manage their own data consumption
|
|
439
|
+
// (e.g., for null termination checks, though this is now handled internally by block readers).
|
|
440
|
+
blockDataBuffer buf.Read
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
func (g *genericBlockReaderWrapper) Read(parentBuf buf.Read) (interface{}, error) {
|
|
444
|
+
val, err := g.coreRead(parentBuf)
|
|
445
|
+
if err != nil {
|
|
446
|
+
return nil, err
|
|
447
|
+
}
|
|
448
|
+
// Null termination for strings is handled by the underlying block.Reader implementations
|
|
449
|
+
// (e.g., LabelBlockReader) themselves, so no additional logic is needed here.
|
|
450
|
+
return val, nil
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// makeBlockReader creates a new block reader (wrapped by genericBlockReaderWrapper)
|
|
454
|
+
// based on the value's wire type, deduplication flag, and block key.
|
|
455
|
+
// It sources the block's data buffer from the MessageSlicer.
|
|
456
|
+
func (ad *ArgoDecoder) makeBlockReader(valueWireType wire.Type, dedupe bool, key wire.BlockKey) (anyBlockReader, error) {
|
|
457
|
+
// Each new block type gets its own data buffer from the slicer,
|
|
458
|
+
// unless HeaderInlineEverythingFlag is set, in which case all readers use the core buffer.
|
|
459
|
+
blockDataForReader := ad.slicer.NextBlock()
|
|
460
|
+
if blockDataForReader == nil {
|
|
461
|
+
// This occurs if slicer.NextBlock() returns nil, meaning no more distinct blocks
|
|
462
|
+
// are available from the message segments.
|
|
463
|
+
if !ad.slicer.Header().GetFlag(header.HeaderInlineEverythingFlag) {
|
|
464
|
+
return nil, fmt.Errorf("no more blocks available in slicer for key %s; schema may expect more blocks than provided in message", key)
|
|
465
|
+
}
|
|
466
|
+
// If HeaderInlineEverythingFlag is true, all "block" data is part of the core buffer.
|
|
467
|
+
// The slicer.NextBlock() will return the coreBuffer in this mode.
|
|
468
|
+
// If it's still nil here, it means slicer.Core() itself is nil, which is unexpected.
|
|
469
|
+
// However, current slicer.NextBlock() logic should return slicer.Core() if the flag is set.
|
|
470
|
+
// Re-assign for clarity if HeaderInlineEverythingFlag is set and NextBlock() somehow wasn't core.
|
|
471
|
+
blockDataForReader = ad.slicer.Core()
|
|
472
|
+
if blockDataForReader == nil {
|
|
473
|
+
// This would be a critical issue with slicer initialization or logic.
|
|
474
|
+
return nil, fmt.Errorf("internal error: core buffer is nil in inline-everything mode for key %s", key)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
var coreReadFunc func(parentBuf buf.Read) (interface{}, error)
|
|
479
|
+
shouldReadNullTerminator := false
|
|
480
|
+
|
|
481
|
+
switch t := valueWireType.(type) {
|
|
482
|
+
case wire.StringType:
|
|
483
|
+
shouldReadNullTerminator = ad.slicer.Header().GetFlag(header.HeaderNullTerminatedStringsFlag)
|
|
484
|
+
fromBytes := func(b []byte) string { return string(b) }
|
|
485
|
+
if dedupe {
|
|
486
|
+
r := block.NewDeduplicatingLabelBlockReader[string](blockDataForReader, fromBytes, shouldReadNullTerminator)
|
|
487
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
488
|
+
} else {
|
|
489
|
+
r := block.NewLabelBlockReader[string](blockDataForReader, fromBytes, shouldReadNullTerminator)
|
|
490
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
491
|
+
}
|
|
492
|
+
case wire.BytesType:
|
|
493
|
+
fromBytes := func(b []byte) []byte { return b } // No copy, direct use
|
|
494
|
+
if dedupe {
|
|
495
|
+
// BytesType never has null termination, so pass false
|
|
496
|
+
r := block.NewDeduplicatingLabelBlockReader[[]byte](blockDataForReader, fromBytes, false)
|
|
497
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
498
|
+
} else {
|
|
499
|
+
// BytesType never has null termination, so pass false
|
|
500
|
+
r := block.NewLabelBlockReader[[]byte](blockDataForReader, fromBytes, false)
|
|
501
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
502
|
+
}
|
|
503
|
+
case wire.VarintType:
|
|
504
|
+
// Deduping VARINT not typically done this way via LabelBlockReader.
|
|
505
|
+
if dedupe {
|
|
506
|
+
return nil, fmt.Errorf("unimplemented: deduping VARINT with LabelBlockReader for key %s", key)
|
|
507
|
+
}
|
|
508
|
+
// UnlabeledVarIntBlockReader reads varint directly from its data buffer (blockDataForReader).
|
|
509
|
+
// The parentBuf (core context) is not used by its Read method for label.
|
|
510
|
+
r := block.NewUnlabeledVarIntBlockReader(blockDataForReader)
|
|
511
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
512
|
+
case wire.Float64Type:
|
|
513
|
+
if dedupe {
|
|
514
|
+
return nil, fmt.Errorf("unimplemented: deduping FLOAT64 for key %s", key)
|
|
515
|
+
}
|
|
516
|
+
// FixedSizeBlockReader for FLOAT64 reads from its data buffer. No label in parentBuf.
|
|
517
|
+
fromBytes := func(b []byte) float64 { return math.Float64frombits(binary.LittleEndian.Uint64(b)) }
|
|
518
|
+
r := block.NewFixedSizeBlockReader[float64](blockDataForReader, fromBytes, 8) // Float64 is 8 bytes
|
|
519
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
520
|
+
|
|
521
|
+
case wire.FixedType:
|
|
522
|
+
if dedupe {
|
|
523
|
+
return nil, fmt.Errorf("unimplemented: deduping FIXED for key %s", key)
|
|
524
|
+
}
|
|
525
|
+
// FixedSizeBlockReader for FIXED reads from its data buffer. No label in parentBuf.
|
|
526
|
+
fromBytes := func(b []byte) []byte { return b }
|
|
527
|
+
r := block.NewFixedSizeBlockReader[[]byte](blockDataForReader, fromBytes, t.Length)
|
|
528
|
+
coreReadFunc = func(pbuf buf.Read) (interface{}, error) { return r.Read(pbuf) }
|
|
529
|
+
default:
|
|
530
|
+
return nil, fmt.Errorf("unsupported block value type %s for key %s", wire.Print(valueWireType), key)
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return &genericBlockReaderWrapper{
|
|
534
|
+
coreRead: coreReadFunc,
|
|
535
|
+
blockDataBuffer: blockDataForReader,
|
|
536
|
+
}, nil
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// MessageSlicer is responsible for parsing an Argo message into its constituent parts:
|
|
540
|
+
// the header, data blocks (if any), and the core data.
|
|
541
|
+
// It provides buffered views (buf.Read) into these parts without copying the underlying message data.
|
|
542
|
+
type MessageSlicer struct {
|
|
543
|
+
hdr *header.Header
|
|
544
|
+
coreBuffer buf.Read
|
|
545
|
+
allSegments [][]byte // Stores all byte slices: data blocks first, then the core data as the last segment.
|
|
546
|
+
nextBlockIndex int // Tracks the next data block to be vended by NextBlock().
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// NewMessageSlicer creates a MessageSlicer from a buffer containing the entire Argo message.
|
|
550
|
+
// It reads the header and then parses out the block segments and the final core data segment
|
|
551
|
+
// based on length prefixes, unless the HeaderInlineEverythingFlag is set.
|
|
552
|
+
func NewMessageSlicer(fullMessageBuf buf.Read) (*MessageSlicer, error) {
|
|
553
|
+
s := &MessageSlicer{}
|
|
554
|
+
|
|
555
|
+
s.hdr = header.NewHeader()
|
|
556
|
+
if err := s.hdr.Read(fullMessageBuf); err != nil {
|
|
557
|
+
return nil, fmt.Errorf("failed to read header: %w", err)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if s.hdr.GetFlag(header.HeaderInlineEverythingFlag) {
|
|
561
|
+
// The rest of the buffer is the core. There are no separate blocks.
|
|
562
|
+
remainingBytes := make([]byte, fullMessageBuf.Len()-int(fullMessageBuf.Position()))
|
|
563
|
+
_, err := io.ReadFull(fullMessageBuf, remainingBytes)
|
|
564
|
+
if err != nil {
|
|
565
|
+
return nil, fmt.Errorf("failed to read inline core data: %w", err)
|
|
566
|
+
}
|
|
567
|
+
s.allSegments = [][]byte{remainingBytes}
|
|
568
|
+
s.coreBuffer = buf.NewBufReadonly(remainingBytes)
|
|
569
|
+
|
|
570
|
+
} else {
|
|
571
|
+
// Read all length-prefixed segments. The last one is the core.
|
|
572
|
+
var segments [][]byte
|
|
573
|
+
// fullMessageBuf is now positioned after the header.
|
|
574
|
+
for fullMessageBuf.Position() < int64(fullMessageBuf.Len()) {
|
|
575
|
+
lengthLabel, err := label.Read(fullMessageBuf)
|
|
576
|
+
if err != nil {
|
|
577
|
+
// If EOF and we expected more segments, or segments is empty, it's an error.
|
|
578
|
+
if err == io.EOF && len(segments) > 0 { // EOF after reading some blocks, means core might be missing length
|
|
579
|
+
return nil, fmt.Errorf("unexpected EOF after reading %d blocks, expecting core: %w", len(segments), err)
|
|
580
|
+
}
|
|
581
|
+
return nil, fmt.Errorf("failed to read segment length label: %w", err)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
blockLengthVal := lengthLabel.Value().Int64()
|
|
585
|
+
if blockLengthVal < 0 {
|
|
586
|
+
return nil, fmt.Errorf("invalid negative segment length: %d", blockLengthVal)
|
|
587
|
+
}
|
|
588
|
+
blockLength := int(blockLengthVal)
|
|
589
|
+
|
|
590
|
+
if fullMessageBuf.Position()+int64(blockLength) > int64(fullMessageBuf.Len()) {
|
|
591
|
+
return nil, fmt.Errorf("segment length %d exceeds remaining buffer size %d", blockLength, int64(fullMessageBuf.Len())-fullMessageBuf.Position())
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
segmentBytes := make([]byte, blockLength)
|
|
595
|
+
n, err := io.ReadFull(fullMessageBuf, segmentBytes)
|
|
596
|
+
if err != nil {
|
|
597
|
+
return nil, fmt.Errorf("failed to read segment data (expected %d, got %d): %w", blockLength, n, err)
|
|
598
|
+
}
|
|
599
|
+
segments = append(segments, segmentBytes)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if len(segments) == 0 {
|
|
603
|
+
// This implies header was read, but no blocks and no core followed.
|
|
604
|
+
// The spec implies at least a core (even if empty) prefixed by its length.
|
|
605
|
+
return nil, fmt.Errorf("no blocks or core data found after header")
|
|
606
|
+
}
|
|
607
|
+
s.allSegments = segments
|
|
608
|
+
s.coreBuffer = buf.NewBufReadonly(s.allSegments[len(s.allSegments)-1])
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return s, nil
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Header returns the parsed message header.
|
|
615
|
+
func (s *MessageSlicer) Header() *header.Header {
|
|
616
|
+
return s.hdr
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Core returns a read buffer for the core data part of the message.
|
|
620
|
+
// This buffer contains the main payload after all block definitions.
|
|
621
|
+
func (s *MessageSlicer) Core() buf.Read {
|
|
622
|
+
return s.coreBuffer
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// NextBlock returns a read buffer for the next data block in the message.
|
|
626
|
+
// If the HeaderInlineEverythingFlag is set in the header, this method
|
|
627
|
+
// will repeatedly return the coreBuffer, as all data is considered inline.
|
|
628
|
+
// Otherwise, it iterates through the pre-parsed data block segments.
|
|
629
|
+
// It returns nil if all data blocks have been vended or if in inline mode
|
|
630
|
+
// and no more distinct blocks were expected by the schema logic.
|
|
631
|
+
func (s *MessageSlicer) NextBlock() buf.Read {
|
|
632
|
+
if s.hdr.GetFlag(header.HeaderInlineEverythingFlag) {
|
|
633
|
+
// In inline mode, the "block" is the core itself.
|
|
634
|
+
// The same coreBuffer instance is returned. Reads from this buffer
|
|
635
|
+
// will advance its position, which is the expected behavior for inline scalar values.
|
|
636
|
+
return s.coreBuffer
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Not inlineEverything: vend distinct block segments from allSegments.
|
|
640
|
+
// allSegments contains data blocks followed by the core data as the last element.
|
|
641
|
+
// We only vend actual data blocks here (i.e., segments before the final core segment).
|
|
642
|
+
if s.nextBlockIndex < len(s.allSegments)-1 {
|
|
643
|
+
blockData := s.allSegments[s.nextBlockIndex]
|
|
644
|
+
s.nextBlockIndex++
|
|
645
|
+
return buf.NewBufReadonly(blockData)
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// All distinct data blocks have been vended.
|
|
649
|
+
// Subsequent calls for new block types (if the schema expects more than were in the message)
|
|
650
|
+
// will receive nil.
|
|
651
|
+
return nil
|
|
652
|
+
}
|