diff options
author | Alan Pearce | 2024-05-07 21:32:36 +0200 |
---|---|---|
committer | Alan Pearce | 2024-05-07 21:32:36 +0200 |
commit | 212e5cf6621c99e46dbb37c860dab8938968bb19 (patch) | |
tree | abd06307e406290c17f453360e92dc6462f5533e | |
parent | 32c4f1ddd704984dad79ad059619b127dcc7de2f (diff) | |
download | searchix-212e5cf6621c99e46dbb37c860dab8938968bb19.tar.lz searchix-212e5cf6621c99e46dbb37c860dab8938968bb19.tar.zst searchix-212e5cf6621c99e46dbb37c860dab8938968bb19.zip |
feat: search multiple sources
-rw-r--r-- | frontend/templates/blocks/search.gotmpl | 2 | ||||
-rw-r--r-- | frontend/templates/index.gotmpl | 6 | ||||
-rw-r--r-- | internal/search/search.go | 46 | ||||
-rw-r--r-- | internal/server/server.go | 48 |
4 files changed, 60 insertions, 42 deletions
diff --git a/frontend/templates/blocks/search.gotmpl b/frontend/templates/blocks/search.gotmpl index b03410c..a4f0ee5 100644 --- a/frontend/templates/blocks/search.gotmpl +++ b/frontend/templates/blocks/search.gotmpl @@ -2,7 +2,7 @@ {{- template "js" . }} {{- define "main" }} - <form id="search" action="/options/{{ .Source }}/results"> + <form id="search" action="results"> <label for="query">{{ sourceName .Source }} option search</label> <fieldset> <input id="query" name="query" type="search" value="{{ .Query }}" /> diff --git a/frontend/templates/index.gotmpl b/frontend/templates/index.gotmpl index d4a46da..c94330a 100644 --- a/frontend/templates/index.gotmpl +++ b/frontend/templates/index.gotmpl @@ -11,9 +11,9 @@ <header> <nav> <h1><a href="/">Searchix</a></h1> - <a href="/search/nixos">NixOS</a> - <a href="/search/darwin">Darwin</a> - <a href="/search/home-manager">Home Manager</a> + <a href="/options/nixos/search">NixOS</a> + <a href="/options/darwin/search">Darwin</a> + <a href="/options/home-manager/search">Home Manager</a> </nav> </header> <main> diff --git a/internal/search/search.go b/internal/search/search.go index fc53ad0..b449512 100644 --- a/internal/search/search.go +++ b/internal/search/search.go @@ -17,15 +17,17 @@ import ( const maxResults = 10 -var index bleve.Index -var docs sync.Map - type Result[T options.NixOption] struct { *bleve.SearchResult Results []T } -func Index() error { +type Index[T options.NixOption] struct { + index bleve.Index + docs *sync.Map +} + +func New[T options.NixOption](kind string) (*Index[T], error) { bleve.SetLog(log.Default()) textFieldMapping := bleve.NewTextFieldMapping() nameMapping := bleve.NewTextFieldMapping() @@ -41,18 +43,19 @@ func Index() error { indexMapping.AddDocumentMapping("option", optionMapping) var err error - index, err = bleve.NewMemOnly(indexMapping) + index, err := bleve.NewMemOnly(indexMapping) // index, err = bleve.New(path.Join(cfg.DataPath, const indexFilename = "index.bleve"), indexMapping) if err != nil { - return errors.WithMessage(err, "error opening index") + return nil, errors.WithMessage(err, "error opening index") } batch := index.NewBatch() - _ = batch - jsonFile, err := os.Open(path.Join("data", "processed", "darwin-options.json")) + var docs sync.Map + + jsonFile, err := os.Open(path.Join("data", "processed", kind+".json")) if err != nil { - return errors.WithMessage(err, "error opening json file") + return nil, errors.WithMessage(err, "error opening json file") } dec := jstream.NewDecoder(jsonFile, 1) @@ -63,35 +66,38 @@ func Index() error { Result: &opt, }) if err != nil { - return errors.WithMessage(err, "could not create struct decoder") + return nil, errors.WithMessage(err, "could not create struct decoder") } for mv := range dec.Stream() { err := ms.Decode(mv.Value) // stores in opt if err != nil { - return errors.WithMessagef(err, "could not decode object into option, object: %#v", mv.Value) + return nil, errors.WithMessagef(err, "could not decode object into option, object: %#v", mv.Value) } docs.Store(opt.Option, opt) err = batch.Index(opt.Option, opt) if err != nil { - return errors.WithMessagef(err, "could not index option %s", opt.Option) + return nil, errors.WithMessagef(err, "could not index option %s", opt.Option) } } err = index.Batch(batch) if err != nil { - return errors.WithMessage(err, "failed to run batch index operation") + return nil, errors.WithMessage(err, "failed to run batch index operation") } - return nil + return &Index[T]{ + index, + &docs, + }, nil } -func Search[T options.NixOption](ctx context.Context, keyword string) (*Result[T], error) { +func (index *Index[T]) Search(ctx context.Context, keyword string) (*Result[T], error) { query := bleve.NewMatchQuery(keyword) search := bleve.NewSearchRequest(query) - bleveResult, err := index.SearchInContext(ctx, search) + bleveResult, err := index.index.SearchInContext(ctx, search) select { case <-ctx.Done(): return nil, ctx.Err() @@ -102,7 +108,7 @@ func Search[T options.NixOption](ctx context.Context, keyword string) (*Result[T results := make([]T, min(maxResults, bleveResult.Total)) for i, result := range bleveResult.Hits { - doc, _ := docs.Load(result.ID) + doc, _ := index.docs.Load(result.ID) results[i] = doc.(T) if i > maxResults { break @@ -115,9 +121,3 @@ func Search[T options.NixOption](ctx context.Context, keyword string) (*Result[T }, nil } } - -func Load(name string) any { - doc, _ := docs.Load(name) - - return doc -} diff --git a/internal/server/server.go b/internal/server/server.go index e3cc82d..3b85061 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -72,10 +72,23 @@ func applyDevModeOverrides(config *cfg.Config) { config.CSP.ConnectSrc = slices.Insert(config.CSP.ConnectSrc, 0, "'self'") } +var index = map[string]*search.Index[options.NixOption]{} + +var sourceFileName = map[string]string{ + "darwin": "darwin-options", + "home-manager": "home-manager-options", + "nixos": "nixos-options-nixos-unstable", +} + func init() { - err := search.Index() - if err != nil { - log.Fatalf("could not build search index, error: %#v", err) + var err error + + for source, filename := range sourceFileName { + index[source], err = search.New(filename) + if err != nil { + log.Fatalf("could not build search index, error: %#v", err) + } + } } @@ -122,19 +135,19 @@ func New(runtimeConfig *Config) (*Server, error) { } }) - mux.HandleFunc("/search/{source}", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/options/{source}/search", func(w http.ResponseWriter, r *http.Request) { source := r.PathValue("source") - switch source { - case "nixos", "darwin", "home-manager": - err := templates["search"].Execute(w, TemplateData{ - LiveReload: jsSnippet, - Source: source, - }) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - default: + if index[source] == nil { http.Error(w, "Unknown source", http.StatusNotFound) + + return + } + err := templates["search"].Execute(w, TemplateData{ + LiveReload: jsSnippet, + Source: source, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) } }) @@ -143,7 +156,12 @@ func New(runtimeConfig *Config) (*Server, error) { source := r.PathValue("source") ctx, cancel := context.WithTimeoutCause(r.Context(), timeout, errors.New("timeout")) defer cancel() - results, err := search.Search(ctx, r.URL.Query().Get("query")) + if index[source] == nil { + http.Error(w, "Unknown source", http.StatusNotFound) + + return + } + results, err := index[source].Search(ctx, r.URL.Query().Get("query")) if err != nil { if err == context.DeadlineExceeded { http.Error(w, "Search timed out", http.StatusInternalServerError) |