From c83d960186a1852560a7179875d610ec3e35093b 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 - Heavily inspired by gitea - add `GetAllIssues` which only receives a paginator and gathers all issues ignoring `repoAt` field Signed-off-by: Seongmin Lee --- .gitignore | 1 + appview/db/issues.go | 56 +++++++++ appview/indexer/base36/base36.go | 20 ++++ appview/indexer/bleve/batch.go | 58 +++++++++ appview/indexer/indexer.go | 27 +++++ appview/indexer/issues/indexer.go | 192 ++++++++++++++++++++++++++++++ appview/indexer/notifier.go | 26 ++++ appview/issues/issues.go | 4 + appview/models/search.go | 23 ++++ appview/pages/pages.go | 1 + appview/state/router.go | 2 +- appview/state/state.go | 10 ++ go.mod | 27 +++++ go.sum | 58 +++++++++ 14 files changed, 504 insertions(+), 1 deletion(-) 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 create mode 100644 appview/models/search.go diff --git a/.gitignore b/.gitignore index e7fdc3d..1a28a53 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ patches .env *.rdb .envrc +*.bleve # Created if following hacking.md genjwks.out /nix/vm-data diff --git a/appview/db/issues.go b/appview/db/issues.go index 5d28656..96ff649 100644 --- a/appview/db/issues.go +++ b/appview/db/issues.go @@ -104,6 +104,62 @@ func GetIssueOwnerDid(e Execer, repoAt syntax.ATURI, issueId int) (string, error return ownerDid, err } +func GetAllIssues(e Execer, page pagination.Page) ([]Issue, error) { + var issues []Issue + rows, err := e.Query( + ` + select + i.id, + i.owner_did, + i.repo_at, + i.issue_id, + i.created, + i.title, + i.body, + i.open, + count(c.id) as comment_count + from + issues i + left join + comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id + group by + i.id + order by i.created desc + limit ? offset ?`, + page.Limit, + page.Offset, + ) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var issue Issue + var createdAt string + var metadata IssueMetadata + err := rows.Scan(&issue.ID, &issue.OwnerDid, &issue.RepoAt, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open, &metadata.CommentCount) + if err != nil { + return nil, err + } + + createdTime, err := time.Parse(time.RFC3339, createdAt) + if err != nil { + return nil, err + } + issue.Created = createdTime + issue.Metadata = &metadata + + issues = append(issues, issue) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return issues, nil +} + func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) { var issues []Issue openValue := 0 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..6fc2dce --- /dev/null +++ b/appview/indexer/indexer.go @@ -0,0 +1,27 @@ +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" +) + +type Indexer struct { + Issues *issues_indexer.Indexer + notify.BaseNotifier +} + +func New() *Indexer { + return &Indexer { + issues_indexer.NewIndexer("indexes.bleve"), + notify.BaseNotifier{}, + } +} + +// 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..d6b28af --- /dev/null +++ b/appview/indexer/issues/indexer.go @@ -0,0 +1,192 @@ +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" + "tangled.sh/tangled.sh/core/appview/indexer/bleve" + "tangled.sh/tangled.sh/core/appview/models" + "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 { + page := pagination.FirstPage() + for { + issues, err := db.GetAllIssues(e, page) + if err != nil { + return err + } + var dataList []*IssueData + for _, issue := range issues { + issue, _, err := db.GetIssueWithComments(e, issue.RepoAt, issue.IssueId) + if err != nil { + return err + } + dataList = append(dataList, &IssueData{ + ID: issue.ID, + IssueID: issue.IssueId, + Title: issue.Title, + Body: issue.Body, + IsOpen: issue.Open, + }) + } + err = ix.Index(ctx, dataList...) + if err != nil { + return err + } + if len(issues) < page.Limit { + break + } + page = page.Next() + } + 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 SearchResult struct { + Hits []int64 + Total uint64 +} + +const maxBatchSize = 20 + +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 models.IssueSearchOptions) (*SearchResult, error) { + var queries []query.Query + + if opts.Keyword != "" { + queries = append(queries, bleve.NewDisjunctionQuery( + matchAndQuery(opts.Keyword, "title"), + matchAndQuery(opts.Keyword, "body"), + )) + } + 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..2c04f3d --- /dev/null +++ b/appview/indexer/notifier.go @@ -0,0 +1,26 @@ +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) NewPullComment(ctx context.Context, comment *db.PullComment) { + panic("unimplemented") +} diff --git a/appview/issues/issues.go b/appview/issues/issues.go index 7693078..159479b 100644 --- a/appview/issues/issues.go +++ b/appview/issues/issues.go @@ -18,6 +18,7 @@ import ( "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/appview/config" "tangled.sh/tangled.sh/core/appview/db" + 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" @@ -35,6 +36,7 @@ type Issues struct { db *db.DB config *config.Config notifier notify.Notifier + indexer *issues_indexer.Indexer } func New( @@ -45,6 +47,7 @@ func New( db *db.DB, config *config.Config, notifier notify.Notifier, + indexer *issues_indexer.Indexer, ) *Issues { return &Issues{ oauth: oauth, @@ -54,6 +57,7 @@ func New( db: db, config: config, notifier: notifier, + indexer: indexer, } } diff --git a/appview/models/search.go b/appview/models/search.go new file mode 100644 index 0000000..c6793e5 --- /dev/null +++ b/appview/models/search.go @@ -0,0 +1,23 @@ +package models + +import "tangled.sh/tangled.sh/core/appview/pagination" + +type IssueSearchOptions struct { + Keyword string + RepoAt string + IsOpen bool + + Page pagination.Page +} + +// func (so *SearchOptions) ToFilters() []filter { +// var filters []filter +// if so.IsOpen != nil { +// openValue := 0 +// if *so.IsOpen { +// openValue = 1 +// } +// filters = append(filters, FilterEq("open", openValue)) +// } +// return filters +// } diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 6697ffa..639b4b2 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -782,6 +782,7 @@ type RepoIssuesParams struct { Issues []db.Issue Page pagination.Page FilteringByOpen bool + FilterQuery string } func (p *Pages) RepoIssues(w io.Writer, params RepoIssuesParams) error { diff --git a/appview/state/router.go b/appview/state/router.go index 81eea64..731d682 100644 --- a/appview/state/router.go +++ b/appview/state/router.go @@ -222,7 +222,7 @@ func (s *State) StringsRouter(mw *middleware.Middleware) 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.notifier) + issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier, s.indexer.Issues) return issues.Router(mw) } diff --git a/appview/state/state.go b/appview/state/state.go index e09e67e..8657670 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -20,6 +20,7 @@ import ( "tangled.sh/tangled.sh/core/appview/cache/session" "tangled.sh/tangled.sh/core/appview/config" "tangled.sh/tangled.sh/core/appview/db" + "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" @@ -37,6 +38,7 @@ import ( type State struct { db *db.DB notifier notify.Notifier + indexer *indexer.Indexer oauth *oauth.OAuth enforcer *rbac.Enforcer pages *pages.Pages @@ -56,6 +58,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) @@ -136,11 +144,13 @@ func Make(ctx context.Context, config *config.Config) (*State, error) { if !config.Core.Dev { notifiers = append(notifiers, posthogService.NewPosthogNotifier(posthog)) } + notifiers = append(notifiers, indexer) notifier := notify.NewMergedNotifier(notifiers...) state := &State{ d, notifier, + indexer, oauth, enforcer, pgs, diff --git a/go.mod b/go.mod index 03793b3..8ac54c2 100644 --- a/go.mod +++ b/go.mod @@ -53,10 +53,30 @@ require ( dario.cat/mergo v1.0.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect + github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect github.com/alecthomas/repr v0.4.0 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // 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.3 // indirect + github.com/blevesearch/bleve_index_api v1.2.8 // indirect + github.com/blevesearch/geo v0.2.4 // 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/cenkalti/backoff/v4 v4.3.0 // indirect @@ -88,6 +108,8 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.3 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect @@ -113,6 +135,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.3.0 // indirect @@ -127,8 +150,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 @@ -156,6 +182,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.62.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect diff --git a/go.sum b/go.sum index c1ffdc2..3fd2b1a 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.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= github.com/ProtonMail/go-crypto v1.3.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.3 h1:9l1xtKaETv64SZc1jc4Sy0N804laSa/LeMbYddq1YEM= +github.com/blevesearch/bleve/v2 v2.5.3/go.mod h1:Z/e8aWjiq8HeX+nW8qROSxiE0830yQA071dwR3yoMzw= +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.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk= +github.com/blevesearch/geo v0.2.4/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-20250724221105-5827c8fb61bb h1:BqMNDZMfXwiRTJ6NvQotJ0qInn37JH5U8E+TF01CFHQ= github.com/bluesky-social/indigo v0.0.0-20250724221105-5827c8fb61bb/go.mod h1:0XUyOCRtL4/OiyeqMTmr6RlVHQMDgw3LS7CfibuZR5Q= github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1 h1:CFvRtYNSnWRAi/98M3O466t9dYuwtesNbu6FVPymRrA= @@ -152,6 +193,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= @@ -163,6 +208,7 @@ 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/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +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= @@ -245,6 +291,8 @@ github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6 github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= 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= @@ -296,10 +344,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= @@ -439,6 +494,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.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= @@ -640,6 +697,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