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
slidge_whatsapp/session.go
CHANGED
|
@@ -4,6 +4,7 @@ import (
|
|
|
4
4
|
// Standard library.
|
|
5
5
|
"bytes"
|
|
6
6
|
"context"
|
|
7
|
+
"encoding/json"
|
|
7
8
|
"errors"
|
|
8
9
|
"fmt"
|
|
9
10
|
"image/jpeg"
|
|
@@ -452,12 +453,16 @@ func (s *Session) GetContacts(refresh bool) ([]Contact, error) {
|
|
|
452
453
|
|
|
453
454
|
var contacts []Contact
|
|
454
455
|
for jid, info := range data {
|
|
456
|
+
c := newContact(jid, info)
|
|
457
|
+
if c.JID == "" {
|
|
458
|
+
continue
|
|
459
|
+
}
|
|
460
|
+
|
|
455
461
|
if err = s.client.SubscribePresence(jid); err != nil {
|
|
456
462
|
s.gateway.logger.Warnf("Failed to subscribe to presence for %s", jid)
|
|
457
463
|
}
|
|
458
464
|
|
|
459
|
-
|
|
460
|
-
contacts = append(contacts, c.Contact)
|
|
465
|
+
contacts = append(contacts, c)
|
|
461
466
|
}
|
|
462
467
|
|
|
463
468
|
return contacts, nil
|
|
@@ -466,6 +471,7 @@ func (s *Session) GetContacts(refresh bool) ([]Contact, error) {
|
|
|
466
471
|
// GetGroups returns a list of all group-chats currently joined in WhatsApp, along with additional
|
|
467
472
|
// information on present participants.
|
|
468
473
|
func (s *Session) GetGroups() ([]Group, error) {
|
|
474
|
+
var ctx = context.Background()
|
|
469
475
|
if s.client == nil || s.client.Store.ID == nil {
|
|
470
476
|
return nil, fmt.Errorf("cannot get groups for unauthenticated session")
|
|
471
477
|
}
|
|
@@ -477,7 +483,7 @@ func (s *Session) GetGroups() ([]Group, error) {
|
|
|
477
483
|
|
|
478
484
|
var groups []Group
|
|
479
485
|
for _, info := range data {
|
|
480
|
-
groups = append(groups, newGroup(s.client, info))
|
|
486
|
+
groups = append(groups, newGroup(ctx, s.client, info))
|
|
481
487
|
}
|
|
482
488
|
|
|
483
489
|
return groups, nil
|
|
@@ -486,6 +492,7 @@ func (s *Session) GetGroups() ([]Group, error) {
|
|
|
486
492
|
// CreateGroup attempts to create a new WhatsApp group for the given human-readable name and
|
|
487
493
|
// participant JIDs given.
|
|
488
494
|
func (s *Session) CreateGroup(name string, participants []string) (Group, error) {
|
|
495
|
+
var ctx = context.Background()
|
|
489
496
|
if s.client == nil || s.client.Store.ID == nil {
|
|
490
497
|
return Group{}, fmt.Errorf("cannot create group for unauthenticated session")
|
|
491
498
|
}
|
|
@@ -501,12 +508,12 @@ func (s *Session) CreateGroup(name string, participants []string) (Group, error)
|
|
|
501
508
|
}
|
|
502
509
|
|
|
503
510
|
req := whatsmeow.ReqCreateGroup{Name: name, Participants: jids}
|
|
504
|
-
info, err := s.client.CreateGroup(req)
|
|
511
|
+
info, err := s.client.CreateGroup(ctx, req)
|
|
505
512
|
if err != nil {
|
|
506
513
|
return Group{}, fmt.Errorf("could not create group: %s", err)
|
|
507
514
|
}
|
|
508
515
|
|
|
509
|
-
return newGroup(s.client, info), nil
|
|
516
|
+
return newGroup(ctx, s.client, info), nil
|
|
510
517
|
}
|
|
511
518
|
|
|
512
519
|
// LeaveGroup attempts to remove our own user from the given WhatsApp group, for the JID given.
|
|
@@ -647,7 +654,7 @@ func (s *Session) UpdateGroupParticipants(resourceID string, participants []Grou
|
|
|
647
654
|
return nil, fmt.Errorf("failed setting group affiliation: %s", err)
|
|
648
655
|
}
|
|
649
656
|
for i := range participants {
|
|
650
|
-
p := newGroupParticipant(participants[i])
|
|
657
|
+
p := newGroupParticipant(ctx, s.client, participants[i])
|
|
651
658
|
if p.JID == "" {
|
|
652
659
|
continue
|
|
653
660
|
}
|
|
@@ -669,9 +676,9 @@ func (s *Session) FindContact(phone string) (Contact, error) {
|
|
|
669
676
|
}
|
|
670
677
|
|
|
671
678
|
jid := types.NewJID(phone, DefaultUserServer)
|
|
672
|
-
if
|
|
673
|
-
if
|
|
674
|
-
return
|
|
679
|
+
if info, err := s.client.Store.Contacts.GetContact(ctx, jid); err == nil && info.Found {
|
|
680
|
+
if c := newContact(jid, info); c.JID != "" {
|
|
681
|
+
return c, nil
|
|
675
682
|
}
|
|
676
683
|
}
|
|
677
684
|
|
|
@@ -747,7 +754,7 @@ func (s *Session) propagateEvent(kind EventKind, payload *EventPayload) {
|
|
|
747
754
|
// errors that occur during processing are logged.
|
|
748
755
|
func (s *Session) handleEvent(evt any) {
|
|
749
756
|
var ctx = context.Background()
|
|
750
|
-
s.gateway.logger.Debugf("Handling event '%T': %+v", evt, evt)
|
|
757
|
+
s.gateway.logger.Debugf("Handling event '%T': %+v", evt, jsonStringer{evt})
|
|
751
758
|
|
|
752
759
|
switch evt := evt.(type) {
|
|
753
760
|
case *events.AppStateSyncComplete:
|
|
@@ -789,24 +796,24 @@ func (s *Session) handleEvent(evt any) {
|
|
|
789
796
|
case waHistorySync.HistorySync_INITIAL_BOOTSTRAP, waHistorySync.HistorySync_RECENT, waHistorySync.HistorySync_ON_DEMAND:
|
|
790
797
|
for _, c := range evt.Data.GetConversations() {
|
|
791
798
|
for _, msg := range c.GetMessages() {
|
|
792
|
-
s.propagateEvent(newEventFromHistory(s.client, msg.GetMessage()))
|
|
799
|
+
s.propagateEvent(newEventFromHistory(ctx, s.client, msg.GetMessage()))
|
|
793
800
|
}
|
|
794
801
|
}
|
|
795
802
|
}
|
|
796
803
|
case *events.Message:
|
|
797
|
-
s.propagateEvent(newMessageEvent(s.client, evt))
|
|
804
|
+
s.propagateEvent(newMessageEvent(ctx, s.client, evt))
|
|
798
805
|
case *events.Receipt:
|
|
799
|
-
s.propagateEvent(newReceiptEvent(evt))
|
|
806
|
+
s.propagateEvent(newReceiptEvent(ctx, s.client, evt))
|
|
800
807
|
case *events.Presence:
|
|
801
808
|
s.propagateEvent(newPresenceEvent(evt))
|
|
802
809
|
case *events.PushName:
|
|
803
810
|
s.propagateEvent(newContactEvent(evt.JID, types.ContactInfo{FullName: evt.NewPushName}))
|
|
804
811
|
case *events.JoinedGroup:
|
|
805
|
-
s.propagateEvent(EventGroup, &EventPayload{Group: newGroup(s.client, &evt.GroupInfo)})
|
|
812
|
+
s.propagateEvent(EventGroup, &EventPayload{Group: newGroup(ctx, s.client, &evt.GroupInfo)})
|
|
806
813
|
case *events.GroupInfo:
|
|
807
|
-
s.propagateEvent(newGroupEvent(evt))
|
|
814
|
+
s.propagateEvent(newGroupEvent(ctx, s.client, evt))
|
|
808
815
|
case *events.ChatPresence:
|
|
809
|
-
s.propagateEvent(newChatStateEvent(evt))
|
|
816
|
+
s.propagateEvent(newChatStateEvent(ctx, s.client, evt))
|
|
810
817
|
case *events.CallOffer:
|
|
811
818
|
s.propagateEvent(newCallEvent(CallIncoming, evt.BasicCallMeta))
|
|
812
819
|
case *events.CallTerminate:
|
|
@@ -817,7 +824,7 @@ func (s *Session) handleEvent(evt any) {
|
|
|
817
824
|
s.gateway.logger.Warnf("Unable to delete local device state on logout: %s", err)
|
|
818
825
|
}
|
|
819
826
|
s.client = nil
|
|
820
|
-
s.propagateEvent(EventLoggedOut,
|
|
827
|
+
s.propagateEvent(EventLoggedOut, &EventPayload{LoggedOut: LoggedOut{Reason: evt.Reason.String()}})
|
|
821
828
|
case *events.PairSuccess:
|
|
822
829
|
if s.client.Store.ID == nil {
|
|
823
830
|
s.gateway.logger.Errorf("Pairing succeeded, but device ID is missing")
|
|
@@ -854,6 +861,16 @@ func (s *Session) handleEvent(evt any) {
|
|
|
854
861
|
}
|
|
855
862
|
}
|
|
856
863
|
|
|
864
|
+
// a JSONStringer is a value that returns a JSON-encoded, multi-line version of itself in calls to
|
|
865
|
+
// [String].
|
|
866
|
+
type jsonStringer struct{ v any }
|
|
867
|
+
|
|
868
|
+
// String returns a multi-line, indented, JSON representation of the [jsonStringer] value.
|
|
869
|
+
func (j jsonStringer) String() string {
|
|
870
|
+
buf, _ := json.MarshalIndent(j.v, "", " ")
|
|
871
|
+
return string(buf)
|
|
872
|
+
}
|
|
873
|
+
|
|
857
874
|
// PtrTo returns a pointer to the given value, and is used for convenience when converting between
|
|
858
875
|
// concrete and pointer values without assigning to a variable.
|
|
859
876
|
func ptrTo[T any](t T) *T {
|
slidge_whatsapp/session.py
CHANGED
|
@@ -6,10 +6,12 @@ from pathlib import Path
|
|
|
6
6
|
from re import search
|
|
7
7
|
from typing import Any, Optional, Union, cast
|
|
8
8
|
|
|
9
|
+
import sqlalchemy
|
|
9
10
|
from aiohttp import ClientSession
|
|
10
11
|
from linkpreview import Link, LinkPreview
|
|
11
12
|
from slidge import BaseSession, FormField, GatewayUser, SearchResult, global_config
|
|
12
13
|
from slidge.contact.roster import ContactIsUser
|
|
14
|
+
from slidge.db.models import ArchivedMessage
|
|
13
15
|
from slidge.util import is_valid_phone_number
|
|
14
16
|
from slidge.util.types import (
|
|
15
17
|
LegacyAttachment,
|
|
@@ -157,17 +159,24 @@ class Session(BaseSession[str, Recipient]):
|
|
|
157
159
|
)
|
|
158
160
|
elif event == whatsapp.EventLoggedOut:
|
|
159
161
|
self.logged = False
|
|
160
|
-
|
|
162
|
+
message = MESSAGE_LOGGED_OUT
|
|
163
|
+
if data.LoggedOut.Reason:
|
|
164
|
+
message += f"\nReason: {data.LoggedOut.Reason}"
|
|
165
|
+
self.send_gateway_message(message)
|
|
161
166
|
self.send_gateway_status("Logged out", show="away")
|
|
162
167
|
elif event == whatsapp.EventContact:
|
|
163
168
|
contact = await self.contacts.add_whatsapp_contact(data.Contact)
|
|
164
|
-
if contact is not None:
|
|
169
|
+
if contact is not None and contact.is_friend:
|
|
165
170
|
await contact.add_to_roster()
|
|
166
171
|
elif event == whatsapp.EventGroup:
|
|
167
172
|
await self.bookmarks.add_whatsapp_group(data.Group)
|
|
168
173
|
elif event == whatsapp.EventPresence:
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
if not whatsapp.IsAnonymousJID(data.Presence.JID):
|
|
175
|
+
contact = await self.contacts.by_legacy_id(data.Presence.JID)
|
|
176
|
+
if contact is not None:
|
|
177
|
+
await contact.update_presence(
|
|
178
|
+
data.Presence.Kind, data.Presence.LastSeen
|
|
179
|
+
)
|
|
171
180
|
elif event == whatsapp.EventChatState:
|
|
172
181
|
await self.handle_chat_state(data.ChatState)
|
|
173
182
|
elif event == whatsapp.EventReceipt:
|
|
@@ -217,12 +226,22 @@ class Session(BaseSession[str, Recipient]):
|
|
|
217
226
|
"""
|
|
218
227
|
contact = await self.__get_contact_or_participant(message.JID, message.GroupJID)
|
|
219
228
|
muc = getattr(contact, "muc", None)
|
|
229
|
+
# Skip handing message that's already in our message archive.
|
|
230
|
+
if (
|
|
231
|
+
muc is not None
|
|
232
|
+
and message.IsHistory
|
|
233
|
+
and await self.__is_message_in_archive(message.ID)
|
|
234
|
+
):
|
|
235
|
+
return
|
|
220
236
|
reply_to = await self.__get_reply_to(message, muc)
|
|
221
237
|
message_timestamp = (
|
|
222
238
|
datetime.fromtimestamp(message.Timestamp, tz=timezone.utc)
|
|
223
239
|
if message.Timestamp > 0
|
|
224
240
|
else None
|
|
225
241
|
)
|
|
242
|
+
if message.GroupInvite.JID:
|
|
243
|
+
text = f"Received group invite for xmpp:{message.GroupInvite.JID} from {contact.name}, auto-joining..."
|
|
244
|
+
self.send_gateway_message(text)
|
|
226
245
|
if message.Kind == whatsapp.MessagePlain:
|
|
227
246
|
body = await self.__get_body(message, muc)
|
|
228
247
|
contact.send_text(
|
|
@@ -543,15 +562,13 @@ class Session(BaseSession[str, Recipient]):
|
|
|
543
562
|
items=[{"phone": cast(str, phone), "jid": contact.jid.bare}],
|
|
544
563
|
)
|
|
545
564
|
|
|
546
|
-
def message_is_carbon(self, c: Recipient, legacy_msg_id: str):
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
stored = self.xmpp.store.sent.get_xmpp_id(self.user_pk, legacy_msg_id)
|
|
554
|
-
return stored is not None
|
|
565
|
+
def message_is_carbon(self, c: Recipient, legacy_msg_id: str) -> bool:
|
|
566
|
+
with self.xmpp.store.session() as orm:
|
|
567
|
+
return bool(
|
|
568
|
+
self.xmpp.store.id_map.get_xmpp(
|
|
569
|
+
orm, c.stored.id, legacy_msg_id, c.is_group
|
|
570
|
+
)
|
|
571
|
+
)
|
|
555
572
|
|
|
556
573
|
def __reset_connected(self):
|
|
557
574
|
if hasattr(self, "_connected") and not self.__connected.done():
|
|
@@ -675,6 +692,16 @@ class Session(BaseSession[str, Recipient]):
|
|
|
675
692
|
Accuracy=int(match.group("acc") or 0),
|
|
676
693
|
)
|
|
677
694
|
|
|
695
|
+
async def __is_message_in_archive(self, legacy_msg_id: str) -> bool:
|
|
696
|
+
with self.xmpp.store.session() as orm:
|
|
697
|
+
return bool(
|
|
698
|
+
orm.scalar(
|
|
699
|
+
sqlalchemy.exists()
|
|
700
|
+
.where(ArchivedMessage.legacy_id == legacy_msg_id)
|
|
701
|
+
.select()
|
|
702
|
+
)
|
|
703
|
+
)
|
|
704
|
+
|
|
678
705
|
async def __get_contact_or_participant(
|
|
679
706
|
self, legacy_contact_id: str, legacy_group_jid: str
|
|
680
707
|
):
|
|
@@ -683,7 +710,12 @@ class Session(BaseSession[str, Recipient]):
|
|
|
683
710
|
"""
|
|
684
711
|
if legacy_group_jid:
|
|
685
712
|
muc = await self.bookmarks.by_legacy_id(legacy_group_jid)
|
|
686
|
-
|
|
713
|
+
if whatsapp.IsAnonymousJID(legacy_contact_id):
|
|
714
|
+
return await muc.get_participant(legacy_contact_id)
|
|
715
|
+
else:
|
|
716
|
+
return await muc.get_participant_by_legacy_id(legacy_contact_id)
|
|
717
|
+
elif whatsapp.IsAnonymousJID(legacy_contact_id):
|
|
718
|
+
raise ValueError("Contact for anonymous JID")
|
|
687
719
|
else:
|
|
688
720
|
return await self.contacts.by_legacy_id(legacy_contact_id)
|
|
689
721
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Automattic Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// Package block provides reader and writer types for processing Argo data blocks.
|
|
2
|
+
// These types handle different encoding strategies such as length-prefixing (with or without deduplication),
|
|
3
|
+
// fixed-size data, and unlabeled varints.
|
|
4
|
+
package block
|
|
5
|
+
|
|
6
|
+
import (
|
|
7
|
+
"fmt"
|
|
8
|
+
"io" // For io.EOF, io.ErrUnexpectedEOF
|
|
9
|
+
|
|
10
|
+
"github.com/beeper/argo-go/label"
|
|
11
|
+
"github.com/beeper/argo-go/pkg/buf"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// FromBytesFunc is a generic function type that defines a conversion from a byte slice
|
|
15
|
+
// to a specific output type `Out`. It is used by various block readers to transform
|
|
16
|
+
// raw bytes read from a block into the desired data type.
|
|
17
|
+
// This corresponds to the `(bytes: Uint8Array) => Out` callback in the TypeScript Argo implementation.
|
|
18
|
+
type FromBytesFunc[Out any] func(bytes []byte) Out
|
|
19
|
+
|
|
20
|
+
// CommonState holds shared state for block readers, primarily the `DataBuf` from which
|
|
21
|
+
// block data is read. It also provides a default `AfterNewRead` hook.
|
|
22
|
+
// Embedding CommonState allows concrete reader types to share this buffer and default hook.
|
|
23
|
+
type CommonState struct {
|
|
24
|
+
// DataBuf is the buffer from which the actual data for this block is read.
|
|
25
|
+
// This is distinct from any "parent" buffer that might contain labels or references.
|
|
26
|
+
DataBuf buf.Read
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// AfterNewRead is a hook method called by some block readers after successfully reading
|
|
30
|
+
// and processing a new value from the block. The default implementation is a no-op.
|
|
31
|
+
// Concrete block reader types can provide their own `AfterNewRead` implementation if specific
|
|
32
|
+
// post-read actions are needed (e.g., updating internal state for deduplication).
|
|
33
|
+
func (cs *CommonState) AfterNewRead() {
|
|
34
|
+
// Default no-op, can be overridden by embedding types.
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// LabelBlockReader reads values from its `DataBuf` where each value is preceded by a
|
|
38
|
+
// length-determining label read from a separate `parentBuf`.
|
|
39
|
+
// It is used for types where each instance in the block is individually length-prefixed.
|
|
40
|
+
// `Out` is the target type of the values read.
|
|
41
|
+
type LabelBlockReader[Out any] struct {
|
|
42
|
+
CommonState // Embeds DataBuf and default AfterNewRead.
|
|
43
|
+
fromBytes FromBytesFunc[Out] // Function to convert raw bytes to Out type.
|
|
44
|
+
readNullTerminator bool // Flag indicating if a null terminator should be read after the data.
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// NewLabelBlockReader creates and returns a new LabelBlockReader.
|
|
48
|
+
// - dataBuf: The buffer from which the actual value data is read (corresponds to `this.buf` in some TS implementations).
|
|
49
|
+
// - fromBytes: A function to convert the raw bytes (read according to the label) into the target type `Out`.
|
|
50
|
+
// - readNullTerminator: If true, an extra null byte is read and discarded from `dataBuf` after reading the value's data (used for null-terminated strings).
|
|
51
|
+
func NewLabelBlockReader[Out any](dataBuf buf.Read, fromBytes FromBytesFunc[Out], readNullTerminator bool) *LabelBlockReader[Out] {
|
|
52
|
+
return &LabelBlockReader[Out]{
|
|
53
|
+
CommonState: CommonState{DataBuf: dataBuf},
|
|
54
|
+
fromBytes: fromBytes,
|
|
55
|
+
readNullTerminator: readNullTerminator,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Read decodes a single value. It first reads a label from `parentBuf` to determine the length
|
|
60
|
+
// of the data. Then, it reads that many bytes from its internal `DataBuf`, converts these bytes
|
|
61
|
+
// to the `Out` type using `fromBytes`, and optionally reads a null terminator.
|
|
62
|
+
// It returns the decoded value and an error if any step fails.
|
|
63
|
+
// This reader expects the label to indicate a length; it cannot handle backreferences, null, absent, or error labels directly.
|
|
64
|
+
func (r *LabelBlockReader[Out]) Read(parentBuf buf.Read) (Out, error) {
|
|
65
|
+
var zero Out // Zero value of Out to return on error
|
|
66
|
+
|
|
67
|
+
l, err := label.Read(parentBuf)
|
|
68
|
+
if err != nil {
|
|
69
|
+
return zero, fmt.Errorf("LabelBlockReader: failed to read label from parentBuf: %w", err)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
switch l.Kind() {
|
|
73
|
+
case label.LabelKindBackreference:
|
|
74
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: this type must not use backreferences (label: %s)", l)
|
|
75
|
+
case label.LabelKindLength:
|
|
76
|
+
lengthVal := l.Value().Int64()
|
|
77
|
+
if lengthVal < 0 {
|
|
78
|
+
// label.IsLength() implies non-negative, so this should be an internal inconsistency.
|
|
79
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: negative length (%d) from label %s which has KindLength", lengthVal, l)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if r.DataBuf == nil {
|
|
83
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: DataBuf is nil")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
var bytesToRead []byte
|
|
87
|
+
if lengthVal == 0 {
|
|
88
|
+
bytesToRead = []byte{} // Empty slice for zero length
|
|
89
|
+
} else {
|
|
90
|
+
bytesToRead = make([]byte, int(lengthVal)) // Allocate slice for data
|
|
91
|
+
n, readErr := r.DataBuf.Read(bytesToRead)
|
|
92
|
+
if readErr != nil && readErr != io.EOF { // Any error other than EOF is immediately problematic
|
|
93
|
+
return zero, fmt.Errorf("LabelBlockReader: DataBuf.Read failed for %d bytes: %w", lengthVal, readErr)
|
|
94
|
+
}
|
|
95
|
+
// If EOF was encountered or no error, ensure all requested bytes were actually read.
|
|
96
|
+
if n != int(lengthVal) {
|
|
97
|
+
// This indicates a short read, which is an error here.
|
|
98
|
+
return zero, fmt.Errorf("LabelBlockReader: expected to read %d bytes from DataBuf, but read %d (read error: %v)", lengthVal, n, readErr)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if r.readNullTerminator {
|
|
103
|
+
_, err := r.DataBuf.ReadByte()
|
|
104
|
+
if err != nil {
|
|
105
|
+
return zero, fmt.Errorf("LabelBlockReader: failed to read null terminator: %w", err)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
value := r.fromBytes(bytesToRead)
|
|
110
|
+
r.AfterNewRead() // Call the AfterNewRead hook (defined on CommonState by default)
|
|
111
|
+
return value, nil
|
|
112
|
+
case label.LabelKindNull:
|
|
113
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: reader cannot handle null labels (label: %s)", l)
|
|
114
|
+
case label.LabelKindAbsent:
|
|
115
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: reader cannot handle absent labels (label: %s)", l)
|
|
116
|
+
case label.LabelKindError:
|
|
117
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: reader cannot handle error labels (label: %s)", l)
|
|
118
|
+
default:
|
|
119
|
+
return zero, fmt.Errorf("programmer error: LabelBlockReader: unhandled label kind %s (label: %s)", l.Kind(), l)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// DeduplicatingLabelBlockReader is similar to LabelBlockReader but adds support for deduplication.
|
|
124
|
+
// It reads values from its `DataBuf` that are preceded by a label (read from `parentBuf`).
|
|
125
|
+
// This label can either specify the length of a new value or be a backreference to a previously read value.
|
|
126
|
+
// New values are stored internally to be targets for future backreferences.
|
|
127
|
+
// `Out` is the target type of the values read.
|
|
128
|
+
type DeduplicatingLabelBlockReader[Out any] struct {
|
|
129
|
+
CommonState // Embeds DataBuf and default AfterNewRead.
|
|
130
|
+
fromBytes FromBytesFunc[Out] // Function to convert raw bytes to Out type.
|
|
131
|
+
values []Out // Stores previously seen values for backreferencing.
|
|
132
|
+
readNullTerminator bool // Flag indicating if a null terminator should be read after new data.
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// NewDeduplicatingLabelBlockReader creates and returns a new DeduplicatingLabelBlockReader.
|
|
136
|
+
// - dataBuf: The buffer for reading actual value data.
|
|
137
|
+
// - fromBytes: Function to convert raw bytes to the `Out` type.
|
|
138
|
+
// - values: An initial slice of values; typically empty, will be populated as new unique values are read.
|
|
139
|
+
// - readNullTerminator: If true, an extra null byte is read from `dataBuf` after new string data.
|
|
140
|
+
func NewDeduplicatingLabelBlockReader[Out any](dataBuf buf.Read, fromBytes FromBytesFunc[Out], readNullTerminator bool) *DeduplicatingLabelBlockReader[Out] {
|
|
141
|
+
return &DeduplicatingLabelBlockReader[Out]{
|
|
142
|
+
CommonState: CommonState{DataBuf: dataBuf},
|
|
143
|
+
fromBytes: fromBytes,
|
|
144
|
+
values: make([]Out, 0), // Initialize empty slice for values
|
|
145
|
+
readNullTerminator: readNullTerminator,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Read decodes a single value, handling potential backreferences.
|
|
150
|
+
// It reads a label from `parentBuf`. If the label is a backreference, it returns the previously stored value.
|
|
151
|
+
// If the label indicates a length, it reads the data from `DataBuf`, converts it, stores it for future
|
|
152
|
+
// backreferences, and returns it. Optionally reads a null terminator for new string data.
|
|
153
|
+
// Returns the decoded value and an error if any step fails.
|
|
154
|
+
// This reader cannot handle null, absent, or error labels directly.
|
|
155
|
+
func (r *DeduplicatingLabelBlockReader[Out]) Read(parentBuf buf.Read) (Out, error) {
|
|
156
|
+
var zero Out
|
|
157
|
+
|
|
158
|
+
l, err := label.Read(parentBuf)
|
|
159
|
+
if err != nil {
|
|
160
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: failed to read label from parentBuf: %w", err)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
switch l.Kind() {
|
|
164
|
+
case label.LabelKindBackreference:
|
|
165
|
+
offset, offsetErr := l.ToOffset() // Converts label to backreference offset
|
|
166
|
+
if offsetErr != nil {
|
|
167
|
+
// l.ToOffset() already validates if it's a proper backreference kind.
|
|
168
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: invalid backreference label %s: %w", l, offsetErr)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
idx := int(offset)
|
|
172
|
+
if idx < 0 || idx >= len(r.values) {
|
|
173
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: invalid backreference offset %d (label: %s), current values count: %d", offset, l, len(r.values))
|
|
174
|
+
}
|
|
175
|
+
// The TS `if (value == undefined)` check is implicitly handled by Go's slice indexing:
|
|
176
|
+
// if the index is valid, a value (possibly zero-value) exists.
|
|
177
|
+
value := r.values[idx]
|
|
178
|
+
return value, nil
|
|
179
|
+
|
|
180
|
+
case label.LabelKindLength:
|
|
181
|
+
lengthVal := l.Value().Int64()
|
|
182
|
+
if lengthVal < 0 {
|
|
183
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: negative length (%d) from label %s which has KindLength", lengthVal, l)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if r.DataBuf == nil {
|
|
187
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: DataBuf is nil")
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
var bytesToRead []byte
|
|
191
|
+
if lengthVal == 0 {
|
|
192
|
+
bytesToRead = []byte{}
|
|
193
|
+
} else {
|
|
194
|
+
bytesToRead = make([]byte, int(lengthVal))
|
|
195
|
+
n, readErr := r.DataBuf.Read(bytesToRead)
|
|
196
|
+
if readErr != nil && readErr != io.EOF {
|
|
197
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: DataBuf.Read failed for %d bytes: %w", lengthVal, readErr)
|
|
198
|
+
}
|
|
199
|
+
if n != int(lengthVal) {
|
|
200
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: expected to read %d bytes from DataBuf, but read %d (read error: %v)", lengthVal, n, readErr)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if r.readNullTerminator {
|
|
205
|
+
nul, err := r.DataBuf.ReadByte()
|
|
206
|
+
if err != nil {
|
|
207
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: failed to read null terminator: %w", err)
|
|
208
|
+
}
|
|
209
|
+
if nul != '\000' {
|
|
210
|
+
return zero, fmt.Errorf("DeduplicatingLabelBlockReader: null terminator was not null: %b", nul)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
value := r.fromBytes(bytesToRead)
|
|
215
|
+
r.values = append(r.values, value) // Store the new value for future backreferences
|
|
216
|
+
r.AfterNewRead()
|
|
217
|
+
return value, nil
|
|
218
|
+
|
|
219
|
+
case label.LabelKindNull:
|
|
220
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: reader cannot handle null labels (label: %s)", l)
|
|
221
|
+
case label.LabelKindAbsent:
|
|
222
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: reader cannot handle absent labels (label: %s)", l)
|
|
223
|
+
case label.LabelKindError:
|
|
224
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: reader cannot handle error labels (label: %s)", l)
|
|
225
|
+
default:
|
|
226
|
+
return zero, fmt.Errorf("programmer error: DeduplicatingLabelBlockReader: unhandled label kind %s (label: %s)", l.Kind(), l)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// FixedSizeBlockReader reads values of a predetermined fixed byte length from its `DataBuf`.
|
|
231
|
+
// It does not use labels from a `parentBuf` to determine length, as the length is constant.
|
|
232
|
+
// `Out` is the target type of the values read.
|
|
233
|
+
type FixedSizeBlockReader[Out any] struct {
|
|
234
|
+
CommonState // Embeds DataBuf.
|
|
235
|
+
fromBytes FromBytesFunc[Out] // Function to convert raw bytes to Out type.
|
|
236
|
+
ByteLength int // The fixed number of bytes for each value.
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// NewFixedSizeBlockReader creates and returns a new FixedSizeBlockReader.
|
|
240
|
+
// - dataBuf: The buffer from which fixed-size data chunks are read.
|
|
241
|
+
// - fromBytes: Function to convert the fixed-size byte chunks to the `Out` type.
|
|
242
|
+
// - byteLength: The exact number of bytes that constitutes one value. Must be non-negative, or it panics.
|
|
243
|
+
func NewFixedSizeBlockReader[Out any](dataBuf buf.Read, fromBytes FromBytesFunc[Out], byteLength int) *FixedSizeBlockReader[Out] {
|
|
244
|
+
if byteLength < 0 {
|
|
245
|
+
panic(fmt.Sprintf("FixedSizeBlockReader: byteLength cannot be negative, got %d", byteLength))
|
|
246
|
+
}
|
|
247
|
+
return &FixedSizeBlockReader[Out]{
|
|
248
|
+
CommonState: CommonState{DataBuf: dataBuf},
|
|
249
|
+
fromBytes: fromBytes,
|
|
250
|
+
ByteLength: byteLength,
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Read decodes a fixed-size block from r.DataBuf.
|
|
255
|
+
// parentBuf is ignored by this implementation but included in the signature to potentially
|
|
256
|
+
// match a common interface derived from the abstract BlockReader<Out>.
|
|
257
|
+
func (r *FixedSizeBlockReader[Out]) Read(parentBuf buf.Read) (Out, error) {
|
|
258
|
+
_ = parentBuf // Explicitly acknowledge and ignore parentBuf.
|
|
259
|
+
var zero Out
|
|
260
|
+
|
|
261
|
+
if r.ByteLength < 0 {
|
|
262
|
+
// This state should ideally be prevented by constructor validation.
|
|
263
|
+
return zero, fmt.Errorf("FixedSizeBlockReader: invalid ByteLength %d", r.ByteLength)
|
|
264
|
+
}
|
|
265
|
+
if r.DataBuf == nil {
|
|
266
|
+
return zero, fmt.Errorf("programmer error: FixedSizeBlockReader: DataBuf is nil")
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var bytesToRead []byte
|
|
270
|
+
if r.ByteLength == 0 {
|
|
271
|
+
bytesToRead = []byte{}
|
|
272
|
+
} else {
|
|
273
|
+
bytesToRead = make([]byte, r.ByteLength)
|
|
274
|
+
n, readErr := r.DataBuf.Read(bytesToRead)
|
|
275
|
+
if readErr != nil && readErr != io.EOF {
|
|
276
|
+
return zero, fmt.Errorf("FixedSizeBlockReader: DataBuf.Read failed for %d bytes: %w", r.ByteLength, readErr)
|
|
277
|
+
}
|
|
278
|
+
if n != r.ByteLength {
|
|
279
|
+
return zero, fmt.Errorf("FixedSizeBlockReader: expected to read %d bytes from DataBuf, but read %d (read error: %v)", r.ByteLength, n, readErr)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// The TS comment `// aligned reads` for `new Uint8Array(bytes, bytes.byteOffset, this.byteLength)`
|
|
284
|
+
// is generally not a direct concern for Go's `make([]byte, ...)` which provides a new slice.
|
|
285
|
+
value := r.fromBytes(bytesToRead)
|
|
286
|
+
// No AfterNewRead call in the original TS for this reader.
|
|
287
|
+
return value, nil
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// UnlabeledVarIntBlockReader reads varint-encoded integers directly from its `DataBuf`.
|
|
291
|
+
// It does not use labels from a `parentBuf` as varints are self-delimiting.
|
|
292
|
+
// This reader is specifically for `int64` values after ZigZag decoding.
|
|
293
|
+
type UnlabeledVarIntBlockReader struct {
|
|
294
|
+
CommonState // Embeds DataBuf.
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// NewUnlabeledVarIntBlockReader creates and returns a new UnlabeledVarIntBlockReader.
|
|
298
|
+
// - dataBuf: The buffer from which varint-encoded data is read.
|
|
299
|
+
func NewUnlabeledVarIntBlockReader(dataBuf buf.Read) *UnlabeledVarIntBlockReader {
|
|
300
|
+
return &UnlabeledVarIntBlockReader{
|
|
301
|
+
CommonState: CommonState{DataBuf: dataBuf},
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Read decodes a single varint-encoded integer from `DataBuf` (ignoring `parentBuf`).
|
|
306
|
+
// It performs ZigZag decoding to convert the unsigned varint read from the buffer
|
|
307
|
+
// into a signed `int64`.
|
|
308
|
+
// Returns the decoded `int64` and an error if reading or decoding fails.
|
|
309
|
+
func (r *UnlabeledVarIntBlockReader) Read(parentBuf buf.Read) (int64, error) {
|
|
310
|
+
_ = parentBuf // Explicitly acknowledge and ignore parentBuf.
|
|
311
|
+
|
|
312
|
+
if r.DataBuf == nil {
|
|
313
|
+
return 0, fmt.Errorf("programmer error: UnlabeledVarIntBlockReader: DataBuf is nil")
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
l, err := label.Read(r.DataBuf) // Label (varint) read from r.DataBuf
|
|
317
|
+
if err != nil {
|
|
318
|
+
return 0, fmt.Errorf("UnlabeledVarIntBlockReader: failed to read label from DataBuf: %w", err)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// TS: `Number(Label.read(this.buf))`. This implies getting the numerical value of the label.
|
|
322
|
+
// `l.Value()` returns a *big.Int. Convert to int64.
|
|
323
|
+
// `IsInt64()` checks if the value fits in int64 without loss.
|
|
324
|
+
if !l.Value().IsInt64() {
|
|
325
|
+
return 0, fmt.Errorf("UnlabeledVarIntBlockReader: label value '%s' cannot be represented as int64", l.Value().String())
|
|
326
|
+
}
|
|
327
|
+
// No AfterNewRead call in the original TS for this reader.
|
|
328
|
+
return l.Value().Int64(), nil
|
|
329
|
+
}
|