mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
wip: key-value object
This commit is contained in:
parent
7f969a891f
commit
b9a991e5aa
7 changed files with 364 additions and 4 deletions
28
commonspace/object/keyvalue/element.go
Normal file
28
commonspace/object/keyvalue/element.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package keyvalue
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/anyproto/any-store/anyenc"
|
||||
"github.com/zeebo/blake3"
|
||||
)
|
||||
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
Value []byte
|
||||
TimestampMilli int
|
||||
}
|
||||
|
||||
func (kv KeyValue) AnyEnc(a *anyenc.Arena) *anyenc.Value {
|
||||
obj := a.NewObject()
|
||||
obj.Set("id", a.NewString(kv.Key))
|
||||
if len(kv.Value) == 0 {
|
||||
obj.Set("d", a.NewTrue())
|
||||
} else {
|
||||
obj.Set("v", a.NewBinary(kv.Value))
|
||||
hash := blake3.Sum256(kv.Value)
|
||||
obj.Set("h", a.NewString(hex.EncodeToString(hash[:])))
|
||||
}
|
||||
obj.Set("t", a.NewNumberInt(kv.TimestampMilli))
|
||||
return obj
|
||||
}
|
129
commonspace/object/keyvalue/keyvaluestore/store.go
Normal file
129
commonspace/object/keyvalue/keyvaluestore/store.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
package keyvaluestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
anystore "github.com/anyproto/any-store"
|
||||
"github.com/anyproto/any-store/anyenc"
|
||||
|
||||
"github.com/anyproto/any-sync/app/ldiff"
|
||||
"github.com/anyproto/any-sync/commonspace/object/keyvalue"
|
||||
)
|
||||
|
||||
var (
|
||||
parserPool = &anyenc.ParserPool{}
|
||||
arenaPool = &anyenc.ArenaPool{}
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
any-store document structure:
|
||||
id (string) - key
|
||||
v (bytes) - value
|
||||
h (string) - value hash
|
||||
t (int) - timestamp
|
||||
d (bool) - isDeleted
|
||||
*/
|
||||
|
||||
func NewKeyValueStore(ctx context.Context, collection anystore.Collection) (KeyValueStore, error) {
|
||||
k := &keyValueStore{collection: collection}
|
||||
if err := k.init(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
|
||||
type KeyValueStore interface {
|
||||
Set(ctx context.Context, values ...keyvalue.KeyValue) (err error)
|
||||
ldiff.Remote
|
||||
}
|
||||
|
||||
type keyValueStore struct {
|
||||
collection anystore.Collection
|
||||
ldiff.Diff
|
||||
}
|
||||
|
||||
func (k *keyValueStore) init(ctx context.Context) (err error) {
|
||||
k.Diff = ldiff.New(32, 256)
|
||||
iter, err := k.collection.Find(nil).Iter(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = iter.Close()
|
||||
}()
|
||||
var doc anystore.Doc
|
||||
for iter.Next() {
|
||||
if doc, err = iter.Doc(); err != nil {
|
||||
return
|
||||
}
|
||||
k.Diff.Set(anyEncToElement(doc.Value()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (k *keyValueStore) Set(ctx context.Context, values ...keyvalue.KeyValue) (err error) {
|
||||
elements, err := k.updateValues(ctx, values...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
k.Diff.Set(elements...)
|
||||
return
|
||||
}
|
||||
|
||||
func (k *keyValueStore) updateValues(ctx context.Context, values ...keyvalue.KeyValue) (elements []ldiff.Element, err error) {
|
||||
tx, err := k.collection.WriteTx(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
} else {
|
||||
err = tx.Commit()
|
||||
}
|
||||
}()
|
||||
ctx = tx.Context()
|
||||
parser := parserPool.Get()
|
||||
defer parserPool.Put(parser)
|
||||
arena := arenaPool.Get()
|
||||
defer arenaPool.Put(arena)
|
||||
|
||||
elements = make([]ldiff.Element, 0, len(values))
|
||||
var doc anystore.Doc
|
||||
for _, value := range values {
|
||||
doc, err = k.collection.FindIdWithParser(ctx, parser, value.Key)
|
||||
isNotFound := errors.Is(err, anystore.ErrDocNotFound)
|
||||
if err != nil && !isNotFound {
|
||||
return
|
||||
}
|
||||
if !isNotFound {
|
||||
if doc.Value().GetInt("t") >= value.TimestampMilli {
|
||||
// newest doc is already present
|
||||
continue
|
||||
}
|
||||
}
|
||||
arena.Reset()
|
||||
val := value.AnyEnc(arena)
|
||||
if err = k.collection.UpsertOne(ctx, val); err != nil {
|
||||
return
|
||||
}
|
||||
elements = append(elements, anyEncToElement(val))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func anyEncToElement(val *anyenc.Value) ldiff.Element {
|
||||
head := strconv.Itoa(val.GetInt("t")) + "/"
|
||||
if val.GetBool("d") {
|
||||
head += "del"
|
||||
} else {
|
||||
head += val.GetString("h")
|
||||
}
|
||||
return ldiff.Element{
|
||||
Id: val.GetString("id"),
|
||||
Head: head,
|
||||
}
|
||||
}
|
146
commonspace/object/keyvalue/keyvaluestore/store_test.go
Normal file
146
commonspace/object/keyvalue/keyvaluestore/store_test.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package keyvaluestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
anystore "github.com/anyproto/any-store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/object/keyvalue"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
func TestKeyValueStore_Set(t *testing.T) {
|
||||
var values = []keyvalue.KeyValue{
|
||||
{
|
||||
Key: "1",
|
||||
Value: []byte("1"),
|
||||
TimestampMilli: 1,
|
||||
},
|
||||
{
|
||||
Key: "2",
|
||||
Value: []byte("2"),
|
||||
TimestampMilli: 1,
|
||||
},
|
||||
{
|
||||
Key: "3",
|
||||
Value: []byte("4"),
|
||||
TimestampMilli: 1,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("new", func(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
err := fx.Set(ctx, values...)
|
||||
assert.NoError(t, err)
|
||||
count, _ := fx.coll.Count(ctx)
|
||||
assert.Equal(t, 3, count)
|
||||
assert.Equal(t, 3, fx.Diff.Len())
|
||||
})
|
||||
t.Run("restore", func(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
err := fx.Set(ctx, values...)
|
||||
assert.NoError(t, err)
|
||||
hash := fx.Diff.Hash()
|
||||
kv2, err := NewKeyValueStore(ctx, fx.coll)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, kv2.(*keyValueStore).Diff.Hash(), hash)
|
||||
})
|
||||
t.Run("update", func(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
err := fx.Set(ctx, values...)
|
||||
assert.NoError(t, err)
|
||||
hash := fx.Diff.Hash()
|
||||
|
||||
// do not update because timestamp is not greater
|
||||
require.NoError(t, fx.Set(ctx, keyvalue.KeyValue{Key: "1", TimestampMilli: 1}))
|
||||
assert.Equal(t, hash, fx.Diff.Hash())
|
||||
// should be updated
|
||||
require.NoError(t, fx.Set(ctx, keyvalue.KeyValue{Key: "2", TimestampMilli: 2, Value: []byte("22")}))
|
||||
assert.NotEqual(t, hash, fx.Diff.Hash())
|
||||
})
|
||||
t.Run("delete", func(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
err := fx.Set(ctx, values...)
|
||||
assert.NoError(t, err)
|
||||
hash := fx.Diff.Hash()
|
||||
|
||||
require.NoError(t, fx.Set(ctx, keyvalue.KeyValue{Key: "1", TimestampMilli: 3}))
|
||||
assert.NotEqual(t, hash, fx.Diff.Hash())
|
||||
})
|
||||
}
|
||||
|
||||
func TestKeyValueStore_E2E(t *testing.T) {
|
||||
fx1 := newFixture(t)
|
||||
fx2 := newFixture(t)
|
||||
|
||||
newIds, changedIds, remodedIds, err := fx1.Diff.Diff(ctx, fx2)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, newIds, 0)
|
||||
assert.Len(t, changedIds, 0)
|
||||
assert.Len(t, remodedIds, 0)
|
||||
|
||||
require.NoError(t, fx1.Set(ctx, []keyvalue.KeyValue{
|
||||
{Key: "1", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "2", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "3", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "4", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "5", Value: []byte("1"), TimestampMilli: 1},
|
||||
}...))
|
||||
|
||||
newIds, changedIds, remodedIds, err = fx1.Diff.Diff(ctx, fx2)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, newIds, 0)
|
||||
assert.Len(t, changedIds, 0)
|
||||
assert.Len(t, remodedIds, 5)
|
||||
|
||||
require.NoError(t, fx2.Set(ctx, []keyvalue.KeyValue{
|
||||
{Key: "1", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "2", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "3", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "4", Value: []byte("1"), TimestampMilli: 1},
|
||||
{Key: "5", Value: []byte("1"), TimestampMilli: 1},
|
||||
}...))
|
||||
|
||||
newIds, changedIds, remodedIds, err = fx1.Diff.Diff(ctx, fx2)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, newIds, 0)
|
||||
assert.Len(t, changedIds, 0)
|
||||
assert.Len(t, remodedIds, 0)
|
||||
}
|
||||
|
||||
func newFixture(t testing.TB) *fixture {
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
require.NoError(t, err)
|
||||
db, err := anystore.Open(ctx, filepath.Join(tmpDir, "test.db"), nil)
|
||||
require.NoError(t, err)
|
||||
coll, err := db.Collection(ctx, "test")
|
||||
require.NoError(t, err)
|
||||
kv, err := NewKeyValueStore(ctx, coll)
|
||||
require.NoError(t, err)
|
||||
fx := &fixture{
|
||||
keyValueStore: kv.(*keyValueStore),
|
||||
db: db,
|
||||
coll: coll,
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
fx.finish(t)
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
})
|
||||
return fx
|
||||
}
|
||||
|
||||
type fixture struct {
|
||||
*keyValueStore
|
||||
db anystore.DB
|
||||
coll anystore.Collection
|
||||
}
|
||||
|
||||
func (fx *fixture) finish(t testing.TB) {
|
||||
assert.NoError(t, fx.db.Close())
|
||||
}
|
|
@ -196,6 +196,29 @@ message AclGetRecordsResponse {
|
|||
repeated bytes records = 1;
|
||||
}
|
||||
|
||||
|
||||
message KVHeadSyncRequest {
|
||||
repeated HeadSyncRange ranges = 3;
|
||||
}
|
||||
|
||||
message KVHeadSyncResponse {
|
||||
repeated HeadSyncResult results = 1;
|
||||
}
|
||||
|
||||
message KVGetValuesRequest {
|
||||
repeated string keys = 1;
|
||||
}
|
||||
|
||||
message KVGetValuesResponse {
|
||||
repeated KeyValue values = 1;
|
||||
}
|
||||
|
||||
message KeyValue {
|
||||
string key = 1;
|
||||
bytes value = 2;
|
||||
int64 timestampMilli = 3;
|
||||
}
|
||||
|
||||
// DiffType is a type of diff
|
||||
enum DiffType {
|
||||
Initial = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@ package coordinatorproto
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/anyproto/any-sync/net/rpc/rpcerr"
|
||||
"github.com/anyproto/any-sync/net/rpc/rpcerr"u
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
16
go.mod
16
go.mod
|
@ -34,7 +34,7 @@ require (
|
|||
go.uber.org/mock v0.5.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.29.0
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/time v0.8.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
@ -43,6 +43,7 @@ require (
|
|||
|
||||
require (
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
||||
github.com/anyproto/any-store v0.1.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
|
@ -51,6 +52,7 @@ require (
|
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/flopp/go-findfont v0.1.0 // indirect
|
||||
github.com/fogleman/gg v1.3.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
|
@ -83,14 +85,17 @@ require (
|
|||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.89.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.8.1 // indirect
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel v1.31.0 // indirect
|
||||
|
@ -98,11 +103,16 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.31.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/image v0.21.0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
golang.org/x/tools v0.27.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
modernc.org/libc v1.61.2 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.34.1 // indirect
|
||||
zombiezen.com/go/sqlite v1.4.0 // indirect
|
||||
)
|
||||
|
|
24
go.sum
24
go.sum
|
@ -6,6 +6,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
|||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
|
||||
github.com/anyproto/any-store v0.1.2 h1:/WKsPOQxK1jOHS7efTIosnyJTvy0O3gYg/DSnt41DT0=
|
||||
github.com/anyproto/any-store v0.1.2/go.mod h1:SDlN2AzysAfs8CDd28rrs6boUUtf5H/ydCvwmj+EbsE=
|
||||
github.com/anyproto/go-chash v0.1.0 h1:I9meTPjXFRfXZHRJzjOHC/XF7Q5vzysKkiT/grsogXY=
|
||||
github.com/anyproto/go-chash v0.1.0/go.mod h1:0UjNQi3PDazP0fINpFYu6VKhuna+W/V+1vpXHAfNgLY=
|
||||
github.com/anyproto/go-slip10 v1.0.0 h1:uAEtSuudR3jJBOfkOXf3bErxVoxbuKwdoJN55M1i6IA=
|
||||
|
@ -58,6 +60,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnN
|
|||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU=
|
||||
github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
|
@ -218,6 +222,8 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n
|
|||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -278,6 +284,8 @@ github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYX
|
|||
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg=
|
||||
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
@ -306,6 +314,8 @@ github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P
|
|||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
|
||||
github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y=
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
|
||||
|
@ -355,6 +365,8 @@ golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
|||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
||||
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
|
||||
|
@ -364,6 +376,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -409,6 +422,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -432,5 +446,15 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
modernc.org/libc v1.61.2 h1:dkO4DlowfClcJYsvf/RiK6fUwvzCQTmB34bJLt0CAGQ=
|
||||
modernc.org/libc v1.61.2/go.mod h1:4QGjNyX3h+rn7V5oHpJY2yH0QN6frt1X+5BkXzwLPCo=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk=
|
||||
modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
|
||||
storj.io/drpc v0.0.34 h1:q9zlQKfJ5A7x8NQNFk8x7eKUF78FMhmAbZLnFK+og7I=
|
||||
storj.io/drpc v0.0.34/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg=
|
||||
zombiezen.com/go/sqlite v1.4.0 h1:N1s3RIljwtp4541Y8rM880qgGIgq3fTD2yks1xftnKU=
|
||||
zombiezen.com/go/sqlite v1.4.0/go.mod h1:0w9F1DN9IZj9AcLS9YDKMboubCACkwYCGkzoy3eG5ik=
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue