2023-09-22 23:22:50 +00:00
|
|
|
/*
|
|
|
|
* LURE - Linux User REpository
|
|
|
|
* Copyright (C) 2023 Elara Musayelyan
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"github.com/twitchtv/twirp"
|
|
|
|
"go.elara.ws/logger/log"
|
2023-09-26 22:38:44 +00:00
|
|
|
"go.elara.ws/lure-web/backend/internal/api"
|
2023-09-22 23:22:50 +00:00
|
|
|
"go.elara.ws/lure/pkg/search"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
)
|
|
|
|
|
|
|
|
type lureWebAPI struct{}
|
|
|
|
|
|
|
|
func (l lureWebAPI) Search(ctx context.Context, req *api.SearchRequest) (*api.SearchResponse, error) {
|
2023-09-22 23:41:43 +00:00
|
|
|
opts := search.Options{
|
2023-09-26 22:38:44 +00:00
|
|
|
Filter: search.Filter(req.FilterType),
|
|
|
|
SortBy: search.SortBy(req.SortBy),
|
|
|
|
Limit: req.Limit,
|
|
|
|
Query: req.Query,
|
2023-09-22 23:41:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if req.FilterValue != nil {
|
|
|
|
opts.FilterValue = *req.FilterValue
|
|
|
|
}
|
|
|
|
|
|
|
|
pkgs, err := search.Search(opts)
|
2023-09-22 23:22:50 +00:00
|
|
|
return &api.SearchResponse{Packages: searchPkgsToAPI(ctx, pkgs)}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l lureWebAPI) GetPkg(ctx context.Context, req *api.GetPackageRequest) (*api.Package, error) {
|
|
|
|
pkg, err := search.GetPkg(req.Repository, req.Name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return searchPkgToAPI(ctx, pkg), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l lureWebAPI) GetBuildScript(ctx context.Context, req *api.GetBuildScriptRequest) (*api.GetBuildScriptResponse, error) {
|
|
|
|
r, err := search.GetScript(req.Repository, req.Name)
|
|
|
|
if err == search.ErrScriptNotFound {
|
|
|
|
return nil, twirp.NewError(twirp.NotFound, err.Error())
|
|
|
|
} else if err == search.ErrInvalidArgument {
|
|
|
|
return nil, twirp.NewError(twirp.InvalidArgument, err.Error())
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := io.ReadAll(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &api.GetBuildScriptResponse{Script: string(data)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func searchPkgsToAPI(ctx context.Context, pkgs []search.Package) []*api.Package {
|
|
|
|
out := make([]*api.Package, len(pkgs))
|
|
|
|
for i, pkg := range pkgs {
|
|
|
|
out[i] = searchPkgToAPI(ctx, pkg)
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func searchPkgToAPI(ctx context.Context, pkg search.Package) *api.Package {
|
|
|
|
return &api.Package{
|
|
|
|
Name: pkg.Name,
|
|
|
|
Repository: pkg.Repository,
|
|
|
|
Version: pkg.Version,
|
|
|
|
Release: int64(pkg.Release),
|
|
|
|
Epoch: ptr(int64(pkg.Epoch)),
|
|
|
|
Description: performTranslation(ctx, pkg.Description),
|
|
|
|
Homepage: performTranslation(ctx, pkg.Homepage),
|
|
|
|
Maintainer: performTranslation(ctx, pkg.Maintainer),
|
|
|
|
Architectures: pkg.Architectures,
|
|
|
|
Licenses: pkg.Licenses,
|
|
|
|
Provides: pkg.Provides,
|
|
|
|
Conflicts: pkg.Conflicts,
|
|
|
|
Replaces: pkg.Replaces,
|
|
|
|
Depends: mapToAPI(pkg.Depends),
|
|
|
|
BuildDepends: mapToAPI(pkg.BuildDepends),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ptr[T any](v T) *T {
|
|
|
|
return &v
|
|
|
|
}
|
|
|
|
|
|
|
|
func mapToAPI(m map[string][]string) map[string]*api.StringList {
|
|
|
|
out := make(map[string]*api.StringList, len(m))
|
|
|
|
for override, list := range m {
|
|
|
|
out[override] = &api.StringList{Entries: list}
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func performTranslation(ctx context.Context, v map[string]string) *string {
|
|
|
|
alVal := ctx.Value(acceptLanguageKey{})
|
|
|
|
langVal := ctx.Value(langParameterKey{})
|
|
|
|
|
|
|
|
if alVal == nil && langVal == nil {
|
|
|
|
val, ok := v[""]
|
|
|
|
if !ok {
|
|
|
|
return ptr("<unknown>")
|
|
|
|
}
|
|
|
|
return &val
|
|
|
|
}
|
|
|
|
|
|
|
|
al, _ := alVal.(string)
|
|
|
|
lang, _ := langVal.(string)
|
|
|
|
|
|
|
|
tags, _, err := language.ParseAcceptLanguage(al)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Error parsing Accept-Language header").Err(err).Send()
|
|
|
|
}
|
|
|
|
|
|
|
|
var bases []string
|
|
|
|
if lang != "" {
|
|
|
|
langTag, err := language.Parse(lang)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Error parsing lang parameter").Err(err).Send()
|
|
|
|
bases = getLangBases(tags)
|
|
|
|
} else {
|
|
|
|
bases = getLangBases(append([]language.Tag{langTag}, tags...))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bases = getLangBases(tags)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(bases) == 1 {
|
|
|
|
bases = []string{"en", ""}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, name := range bases {
|
|
|
|
val, ok := v[name]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return &val
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr("<unknown>")
|
|
|
|
}
|
|
|
|
|
|
|
|
func getLangBases(langs []language.Tag) []string {
|
|
|
|
out := make([]string, len(langs)+1)
|
|
|
|
for i, lang := range langs {
|
|
|
|
base, _ := lang.Base()
|
|
|
|
out[i] = base.String()
|
|
|
|
}
|
|
|
|
out[len(out)-1] = ""
|
|
|
|
return out
|
|
|
|
}
|