From 5dd108643fb06162a61d3ae6b5f00d7aa3ffce65 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Sat, 12 Jul 2025 20:28:10 +0900 Subject: [PATCH] appview: add basic issue indexer Change-Id: ukmllqluzwxxyqwuuknqpxuroyrkpvrw Signed-off-by: Seongmin Lee --- .gitignore | 1 + appview/indexer/base36/base36.go | 20 +++ appview/indexer/bleve/batch.go | 58 +++++++++ appview/indexer/indexer.go | 24 ++++ appview/indexer/issues/indexer.go | 199 ++++++++++++++++++++++++++++++ appview/indexer/notifier.go | 30 +++++ appview/issues/issues.go | 10 ++ appview/notify/merged_notifier.go | 2 +- appview/notify/notifier.go | 2 +- appview/state/router.go | 2 +- appview/state/state.go | 10 ++ flake.nix | 2 +- go.mod | 27 ++++ go.sum | 58 +++++++++ 14 files changed, 441 insertions(+), 4 deletions(-) create mode 100644 appview/indexer/base36/base36.go create mode 100644 appview/indexer/bleve/batch.go create mode 100644 appview/indexer/indexer.go create mode 100644 appview/indexer/issues/indexer.go create mode 100644 appview/indexer/notifier.go diff --git a/.gitignore b/.gitignore index 831abae..dd39420 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ patches .DS_Store .env *.rdb +*.bleve diff --git a/appview/indexer/base36/base36.go b/appview/indexer/base36/base36.go new file mode 100644 index 0000000..d5d3d65 --- /dev/null +++ b/appview/indexer/base36/base36.go @@ -0,0 +1,20 @@ +// mostly copied from gitea/modules/indexer/internal/base32 + +package base36 + +import ( + "fmt" + "strconv" +) + +func Encode(i int64) string { + return strconv.FormatInt(i, 36) +} + +func Decode(s string) (int64, error) { + i, err := strconv.ParseInt(s, 36, 64) + if err != nil { + return 0, fmt.Errorf("invalid base36 integer %q: %w", s, err) + } + return i, nil +} diff --git a/appview/indexer/bleve/batch.go b/appview/indexer/bleve/batch.go new file mode 100644 index 0000000..618564e --- /dev/null +++ b/appview/indexer/bleve/batch.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package bleveutil + +import ( + "github.com/blevesearch/bleve/v2" +) + +// FlushingBatch is a batch of operations that automatically flushes to the +// underlying index once it reaches a certain size. +type FlushingBatch struct { + maxBatchSize int + batch *bleve.Batch + index bleve.Index +} + +// NewFlushingBatch creates a new flushing batch for the specified index. Once +// the number of operations in the batch reaches the specified limit, the batch +// automatically flushes its operations to the index. +func NewFlushingBatch(index bleve.Index, maxBatchSize int) *FlushingBatch { + return &FlushingBatch{ + maxBatchSize: maxBatchSize, + batch: index.NewBatch(), + index: index, + } +} + +// Index add a new index to batch +func (b *FlushingBatch) Index(id string, data any) error { + if err := b.batch.Index(id, data); err != nil { + return err + } + return b.flushIfFull() +} + +// Delete add a delete index to batch +func (b *FlushingBatch) Delete(id string) error { + b.batch.Delete(id) + return b.flushIfFull() +} + +func (b *FlushingBatch) flushIfFull() error { + if b.batch.Size() < b.maxBatchSize { + return nil + } + return b.Flush() +} + +// Flush submit the batch and create a new one +func (b *FlushingBatch) Flush() error { + err := b.index.Batch(b.batch) + if err != nil { + return err + } + b.batch = b.index.NewBatch() + return nil +} diff --git a/appview/indexer/indexer.go b/appview/indexer/indexer.go new file mode 100644 index 0000000..607013a --- /dev/null +++ b/appview/indexer/indexer.go @@ -0,0 +1,24 @@ +package indexer + +import ( + "context" + + "tangled.sh/tangled.sh/core/appview/db" + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" +) + +type Indexer struct { + Issues *issues_indexer.Indexer +} + +func New() *Indexer { + return &Indexer { + issues_indexer.NewIndexer("indexes.bleve"), + } +} + +// Init initializes all indexers +func (ix *Indexer) Init(ctx context.Context, db *db.DB) error { + ix.Issues.Init(ctx, db) + return nil +} diff --git a/appview/indexer/issues/indexer.go b/appview/indexer/issues/indexer.go new file mode 100644 index 0000000..13884b8 --- /dev/null +++ b/appview/indexer/issues/indexer.go @@ -0,0 +1,199 @@ +package issues_indexer + +import ( + "context" + "errors" + "log" + "os" + + "github.com/blevesearch/bleve/v2" + "github.com/blevesearch/bleve/v2/index/upsidedown" + "github.com/blevesearch/bleve/v2/search/query" + "tangled.sh/tangled.sh/core/appview/db" + "tangled.sh/tangled.sh/core/appview/indexer/base36" + bleveutil "tangled.sh/tangled.sh/core/appview/indexer/bleve" + "tangled.sh/tangled.sh/core/appview/pagination" +) + +type Indexer struct { + indexer bleve.Index + path string +} + +func NewIndexer(indexDir string) *Indexer { + return &Indexer{ + path: indexDir, + } +} + +// Init initializes the indexer +func (ix *Indexer) Init(ctx context.Context, e db.Execer) { + existed, err := ix.intialize(ctx) + if err != nil { + log.Fatalf("failed to initialize issue indexer: %v", err) + } + if !existed { + log.Println("Populating the issue indexer") + err := PopulateIndexer(ctx, ix, e) + if err != nil { + log.Fatalf("failed to populate issue indexer: %v", err) + } + } + log.Println("Initialized the issue indexer") +} + +func (ix *Indexer) intialize(_ context.Context) (bool, error) { + if ix.indexer != nil { + return false, errors.New("indexer is already initialized") + } + + indexer, err := openIndexer(ix.path) + if err != nil { + return false, nil + } + if indexer != nil { + ix.indexer = indexer + return true, nil + } + + mapping := bleve.NewIndexMapping() + indexer, err = bleve.New(ix.path, mapping) + if err != nil { + return false, err + } + + ix.indexer = indexer + + return false, nil +} + +func openIndexer(path string) (bleve.Index, error) { + _, err := os.Stat(path) + indexer, err := bleve.Open(path) + if err != nil { + if errors.Is(err, upsidedown.IncompatibleVersion) { + log.Println("Indexer was built with a previous version of bleve, deleting and rebuilding") + return nil, os.RemoveAll(path) + } + return nil, nil + } + return indexer, nil +} + +func PopulateIndexer(ctx context.Context, ix *Indexer, e db.Execer) error { + repos, err := db.GetAllRepos(e, 10) + if err != nil { + return err + } + for _, repo := range repos { + page := pagination.FirstPage() + issues, err := db.GetIssues(e, repo.RepoAt(), true, page) + if err != nil { + return err + } + for _, issue := range issues { + issue, _, err := db.GetIssueWithComments(e, repo.RepoAt(), issue.IssueId) + if err != nil { + return err + } + data := &IssueData { + ID: issue.ID, + IssueID: issue.IssueId, + Title: issue.Title, + Body: issue.Body, + IsOpen: issue.Open, + } + err = ix.Index(ctx, data) + if err != nil { + return err + } + } + } + return nil +} + +// IssueData data stored and will be indexed +type IssueData struct { + ID int64 `json:"id"` + IssueID int `json:"issue_id"` + Title string `json:"title"` + Body string `json:"body"` + + IsOpen bool `json:"is_open"` + Comments []IssueCommentData `json:"comments"` +} + +type IssueCommentData struct { + Body string `json:"body"` +} + +type SearchOptions struct { + Keyword string + IsOpen *bool + + Page pagination.Page +} + +type SearchResult struct { + Hits []int64 + Total uint64 +} + +const maxBatchSize = 16 + +func (ix *Indexer) Index(ctx context.Context, issues ...*IssueData) error { + batch := bleveutil.NewFlushingBatch(ix.indexer, maxBatchSize) + for _, issue := range issues { + if err := batch.Index(base36.Encode(issue.ID), issue); err != nil { + return err + } + } + return batch.Flush() +} + +// Search searches for issues +func (ix *Indexer) Search(ctx context.Context, opts SearchOptions) (*SearchResult, error) { + var queries []query.Query + + if opts.Keyword != "" { + queries = append(queries, bleve.NewDisjunctionQuery( + matchAndQuery(opts.Keyword, "title"), + matchAndQuery(opts.Keyword, "body"), + )) + } + if opts.IsOpen != nil { + queries = append(queries, boolFieldQuery(*opts.IsOpen, "is_open")) + } + // TODO: append more queries + + var indexerQuery query.Query = bleve.NewConjunctionQuery(queries...) + searchReq := bleve.NewSearchRequestOptions(indexerQuery, opts.Page.Limit, opts.Page.Offset, false) + res, err := ix.indexer.SearchInContext(ctx, searchReq) + if err != nil { + return nil, nil + } + ret := &SearchResult{ + Total: res.Total, + Hits: make([]int64, len(res.Hits)), + } + for i, hit := range res.Hits { + id, err := base36.Decode(hit.ID) + if err != nil { + return nil, err + } + ret.Hits[i] = id + } + return ret, nil +} + +func matchAndQuery(keyword, field string) query.Query { + q := bleve.NewMatchQuery(keyword) + q.FieldVal = field + return q +} + +func boolFieldQuery(val bool, field string) query.Query { + q := bleve.NewBoolFieldQuery(val) + q.FieldVal = field + return q +} diff --git a/appview/indexer/notifier.go b/appview/indexer/notifier.go new file mode 100644 index 0000000..ac9f8b6 --- /dev/null +++ b/appview/indexer/notifier.go @@ -0,0 +1,30 @@ +package indexer + +import ( + "context" + + "tangled.sh/tangled.sh/core/appview/db" + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" + "tangled.sh/tangled.sh/core/appview/notify" +) + +var _ notify.Notifier = &Indexer{} + +func (ix *Indexer) NewIssue(ctx context.Context, issue *db.Issue) { + ix.Issues.Index(ctx, &issues_indexer.IssueData{ + ID: issue.ID, + IssueID: issue.IssueId, + Title: issue.Title, + Body: issue.Body, + IsOpen: issue.Open, + Comments: []issues_indexer.IssueCommentData{}, + }) +} + +func (ix *Indexer) NewIssueComment(ctx context.Context, comment db.Comment) { + panic("unimplemented") +} + +func (ix *Indexer) NewPullComment(ctx context.Context, comment db.PullComment) { + panic("unimplemented") +} diff --git a/appview/issues/issues.go b/appview/issues/issues.go index 647bd71..1ff3d6e 100644 --- a/appview/issues/issues.go +++ b/appview/issues/issues.go @@ -20,6 +20,8 @@ import ( "tangled.sh/tangled.sh/core/appview/config" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/idresolver" + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" + "tangled.sh/tangled.sh/core/appview/notify" "tangled.sh/tangled.sh/core/appview/oauth" "tangled.sh/tangled.sh/core/appview/pages" "tangled.sh/tangled.sh/core/appview/pagination" @@ -34,6 +36,8 @@ type Issues struct { db *db.DB config *config.Config posthog posthog.Client + notifier notify.Notifier + indexer *issues_indexer.Indexer } func New( @@ -44,6 +48,8 @@ func New( db *db.DB, config *config.Config, posthog posthog.Client, + notifier notify.Notifier, + indexer *issues_indexer.Indexer, ) *Issues { return &Issues{ oauth: oauth, @@ -53,6 +59,8 @@ func New( db: db, config: config, posthog: posthog, + notifier: notifier, + indexer: indexer, } } @@ -734,6 +742,8 @@ func (rp *Issues) NewIssue(w http.ResponseWriter, r *http.Request) { return } + rp.notifier.NewIssue(r.Context(), issue) + if !rp.config.Core.Dev { err = rp.posthog.Enqueue(posthog.Capture{ DistinctId: user.Did, diff --git a/appview/notify/merged_notifier.go b/appview/notify/merged_notifier.go index 2c78fcb..901cda8 100644 --- a/appview/notify/merged_notifier.go +++ b/appview/notify/merged_notifier.go @@ -18,7 +18,7 @@ func NewMergedNotifier(notifiers ...Notifier) Notifier { var _ Notifier = &mergedNotifier{} -func (m *mergedNotifier) NewIssue(ctx context.Context, issue db.Issue) { +func (m *mergedNotifier) NewIssue(ctx context.Context, issue *db.Issue) { for _, notifier := range m.notifiers { notifier.NewIssue(ctx, issue) } diff --git a/appview/notify/notifier.go b/appview/notify/notifier.go index 44151df..5eff4d3 100644 --- a/appview/notify/notifier.go +++ b/appview/notify/notifier.go @@ -7,7 +7,7 @@ import ( ) type Notifier interface { - NewIssue(ctx context.Context, issue db.Issue) + NewIssue(ctx context.Context, issue *db.Issue) NewIssueComment(ctx context.Context, comment db.Comment) NewPullComment(ctx context.Context, comment db.PullComment) diff --git a/appview/state/router.go b/appview/state/router.go index 1c9aa1c..c75658a 100644 --- a/appview/state/router.go +++ b/appview/state/router.go @@ -191,7 +191,7 @@ func (s *State) SpindlesRouter() http.Handler { } func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { - issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.posthog, s.notifier) + issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.posthog, s.notifier, s.indexer.Issues) return issues.Router(mw) } diff --git a/appview/state/state.go b/appview/state/state.go index f97d41a..11856a2 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -25,6 +25,7 @@ import ( "tangled.sh/tangled.sh/core/appview/config" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/idresolver" + "tangled.sh/tangled.sh/core/appview/indexer" "tangled.sh/tangled.sh/core/appview/notify" "tangled.sh/tangled.sh/core/appview/oauth" "tangled.sh/tangled.sh/core/appview/pages" @@ -39,6 +40,7 @@ import ( type State struct { db *db.DB notifier notify.Notifier + indexer *indexer.Indexer oauth *oauth.OAuth enforcer *rbac.Enforcer tidClock syntax.TIDClock @@ -59,6 +61,12 @@ func Make(ctx context.Context, config *config.Config) (*State, error) { return nil, fmt.Errorf("failed to create db: %w", err) } + indexer := indexer.New() + err = indexer.Init(ctx, d) + if err != nil { + return nil, fmt.Errorf("failed to create indexer: %w", err) + } + enforcer, err := rbac.NewEnforcer(config.Core.DbPath) if err != nil { return nil, fmt.Errorf("failed to create enforcer: %w", err) @@ -137,11 +145,13 @@ func Make(ctx context.Context, config *config.Config) (*State, error) { spindlestream.Start(ctx) notifier := notify.NewMergedNotifier( + indexer, ) state := &State{ d, notifier, + indexer, oauth, enforcer, clock, diff --git a/flake.nix b/flake.nix index b01fc71..2104c2d 100644 --- a/flake.nix +++ b/flake.nix @@ -56,7 +56,7 @@ nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system}); inherit (gitignore.lib) gitignoreSource; mkPackageSet = pkgs: let - goModHash = "sha256-SLi+nALwCd/Lzn3aljwPqCo2UaM9hl/4OAjcHQLt2Bk="; + goModHash = "sha256-N+Rm2PanY+fVRE/6Gaz+y3vSUjqKOtngpkS4fn7VFR0="; sqlite-lib = pkgs.callPackage ./nix/pkgs/sqlite-lib.nix { inherit (pkgs) gcc; inherit sqlite-lib-src; diff --git a/go.mod b/go.mod index 3b1c580..15064af 100644 --- a/go.mod +++ b/go.mod @@ -48,10 +48,30 @@ require ( dario.cat/mergo v1.0.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.2.0 // indirect + github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/avast/retry-go/v4 v4.6.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.22.0 // indirect + github.com/blevesearch/bleve/v2 v2.5.2 // indirect + github.com/blevesearch/bleve_index_api v1.2.8 // indirect + github.com/blevesearch/geo v0.2.3 // indirect + github.com/blevesearch/go-faiss v1.0.25 // indirect + github.com/blevesearch/go-porterstemmer v1.0.3 // indirect + github.com/blevesearch/gtreap v0.1.1 // indirect + github.com/blevesearch/mmap-go v1.0.4 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect + github.com/blevesearch/segment v0.9.1 // indirect + github.com/blevesearch/snowballstem v0.9.0 // indirect + github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect + github.com/blevesearch/vellum v1.1.0 // indirect + github.com/blevesearch/zapx/v11 v11.4.2 // indirect + github.com/blevesearch/zapx/v12 v12.4.2 // indirect + github.com/blevesearch/zapx/v13 v13.4.2 // indirect + github.com/blevesearch/zapx/v14 v14.4.2 // indirect + github.com/blevesearch/zapx/v15 v15.4.2 // indirect + github.com/blevesearch/zapx/v16 v16.2.4 // indirect github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect github.com/casbin/govaluate v1.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -78,6 +98,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -95,6 +117,7 @@ require ( github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.6.0 // indirect github.com/ipfs/go-metrics-interface v0.3.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect @@ -108,8 +131,11 @@ require ( github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/atomicwriter v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect + github.com/mschoch/smat v0.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect @@ -135,6 +161,7 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect + go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect diff --git a/go.sum b/go.sum index 279969c..773d871 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs= github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= +github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= +github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -23,6 +25,45 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= +github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blevesearch/bleve/v2 v2.5.2 h1:Ab0r0MODV2C5A6BEL87GqLBySqp/s9xFgceCju6BQk8= +github.com/blevesearch/bleve/v2 v2.5.2/go.mod h1:5Dj6dUQxZM6aqYT3eutTD/GpWKGFSsV8f7LDidFbwXo= +github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y= +github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0= +github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg= +github.com/blevesearch/geo v0.2.3/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8= +github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U= +github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= +github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= +github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= +github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= +github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= +github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= +github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s= +github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8= +github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= +github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= +github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= +github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= +github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= +github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= +github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w= +github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y= +github.com/blevesearch/zapx/v11 v11.4.2 h1:l46SV+b0gFN+Rw3wUI1YdMWdSAVhskYuvxlcgpQFljs= +github.com/blevesearch/zapx/v11 v11.4.2/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc= +github.com/blevesearch/zapx/v12 v12.4.2 h1:fzRbhllQmEMUuAQ7zBuMvKRlcPA5ESTgWlDEoB9uQNE= +github.com/blevesearch/zapx/v12 v12.4.2/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58= +github.com/blevesearch/zapx/v13 v13.4.2 h1:46PIZCO/ZuKZYgxI8Y7lOJqX3Irkc3N8W82QTK3MVks= +github.com/blevesearch/zapx/v13 v13.4.2/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk= +github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT7fWYz0= +github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8= +github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k= +github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= +github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww= +github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs= github.com/bluesky-social/indigo v0.0.0-20250520232546-236dd575c91e h1:DVD+HxQsDCVJtAkjfIKZVaBNc3kayHaU+A2TJZkFdp4= github.com/bluesky-social/indigo v0.0.0-20250520232546-236dd575c91e/go.mod h1:ovyxp8AMO1Hoe838vMJUbqHTZaAR8ABM3g3TXu+A5Ng= github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1 h1:CFvRtYNSnWRAi/98M3O466t9dYuwtesNbu6FVPymRrA= @@ -143,6 +184,10 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -151,6 +196,7 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -220,6 +266,8 @@ github.com/ipfs/go-test v0.2.1 h1:/D/a8xZ2JzkYqcVcV/7HYlCnc7bv/pKHQiX5TdClkPE= github.com/ipfs/go-test v0.2.1/go.mod h1:dzu+KB9cmWjuJnXFDYJwC25T3j1GcN57byN+ixmK39M= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= @@ -273,10 +321,17 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= @@ -411,6 +466,8 @@ gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRyS gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= @@ -592,6 +649,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= -- 2.43.0