forked from security/hakurei
cmd/pkgserver: api versioning
This commit is contained in:
@@ -10,15 +10,29 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/internal/info"
|
||||
"hakurei.app/internal/rosa"
|
||||
)
|
||||
|
||||
func serveCount(index *PackageIndex) func(http.ResponseWriter, *http.Request) {
|
||||
type InfoPayload struct {
|
||||
Count int `json:"count"`
|
||||
HakureiVersion string `json:"hakurei_version"`
|
||||
}
|
||||
|
||||
func NewInfoPayload(index *PackageIndex) InfoPayload {
|
||||
count := len(index.sorts[0])
|
||||
return InfoPayload{
|
||||
Count: count,
|
||||
HakureiVersion: info.Version(),
|
||||
}
|
||||
}
|
||||
|
||||
func serveInfo(index *PackageIndex) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
count := len(index.names)
|
||||
w.Write([]byte(strconv.Itoa(count)))
|
||||
w.Header().Set("Content-Type", "text/json; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
WritePayload(w, NewInfoPayload(index))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,22 +105,26 @@ func serveGet(index *PackageIndex) func(http.ResponseWriter, *http.Request) {
|
||||
return
|
||||
}
|
||||
values := index.sorts[sort][i:min(i+limit, len(index.sorts[sort]))]
|
||||
payload := NewGetPayload(values)
|
||||
WritePayload(w, NewGetPayload(values))
|
||||
}
|
||||
}
|
||||
|
||||
const ApiVersion = "v1"
|
||||
|
||||
func apiRoutes(index *PackageIndex) {
|
||||
http.HandleFunc(fmt.Sprintf("GET /api/%s/info", ApiVersion), serveInfo(index))
|
||||
http.HandleFunc(fmt.Sprintf("GET /api/%s/get", ApiVersion), serveGet(index))
|
||||
http.HandleFunc(fmt.Sprintf("GET /api/%s/status/", ApiVersion), serveStatus(index))
|
||||
}
|
||||
|
||||
func WritePayload(w http.ResponseWriter, payload any) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Set("Pragma", "no-cache")
|
||||
w.Header().Set("Expires", "0")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
b, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
_, err = bytes.NewBuffer(b).WriteTo(w)
|
||||
err := json.NewEncoder(w).Encode(payload)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
func apiRoutes(index *PackageIndex) {
|
||||
http.HandleFunc("GET /api/count", serveCount(index))
|
||||
http.HandleFunc("GET /api/get", serveGet(index))
|
||||
http.HandleFunc("GET /api/status/", serveStatus(index))
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func createPackageIndex(cache *pkg.Cache, report *rosa.Report) (_ *PackageIndex,
|
||||
statusUrl = ""
|
||||
} else {
|
||||
status = st
|
||||
statusUrl = fmt.Sprintf("/api/status/%s.log", m.Name)
|
||||
statusUrl = fmt.Sprintf("/api/%s/status/%s.log", ApiVersion, m.Name)
|
||||
}
|
||||
entry := PackageIndexEntry{
|
||||
Name: m.Name,
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
//go:generate gocc -a azalea.bnf
|
||||
package azalea
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/container/check"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
Generator
|
||||
}
|
||||
|
||||
func NewParser(gen Generator) *Parser {
|
||||
return &Parser{
|
||||
Generator: gen,
|
||||
}
|
||||
}
|
||||
func (p Parser) Initialise() {
|
||||
|
||||
}
|
||||
|
||||
func (p Parser) Consume(ns string, file io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConsumeDir walks a directory and consumes all Azalea source files within it and all its subdirectories, as long as they end with the .az extension.
|
||||
func (p Parser) ConsumeDir(dir *check.Absolute) error {
|
||||
ds := dir.String()
|
||||
return filepath.WalkDir(ds, func(path string, d fs.DirEntry, err error) (e error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() || !strings.HasSuffix(d.Name(), ".az") {
|
||||
return
|
||||
}
|
||||
rel, e := filepath.Rel(ds, path)
|
||||
ns := strings.TrimSuffix(rel, ".az")
|
||||
f, e := os.Open(path)
|
||||
return p.Consume(ns, f)
|
||||
})
|
||||
}
|
||||
|
||||
// ConsumeAll consumes all provided readers as Azalea source code, each given the namespace `r%d` where `%d` is the index of the reader in the provided arguments.
|
||||
func (p Parser) ConsumeAll(in ...io.Reader) error {
|
||||
for i, r := range in {
|
||||
err := p.Consume("r"+strconv.FormatInt(int64(i), 10), r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConsumeStrings consumes all provided strings as Azalea source code, each given the namespace `s%d` where `%d` is the index of the string in the provided arugments.
|
||||
func (p Parser) ConsumeStrings(in ...string) error {
|
||||
for i, s := range in {
|
||||
err := p.Consume("s"+strconv.FormatInt(int64(i), 10), strings.NewReader(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package azalea
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type Generator interface {
|
||||
Finalise() (error, io.Writer)
|
||||
}
|
||||
|
||||
type JsonGenerator struct {
|
||||
t any
|
||||
}
|
||||
|
||||
func NewJsonGenerator[T any]() JsonGenerator {
|
||||
t := new(T)
|
||||
|
||||
return JsonGenerator{
|
||||
t,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *JsonGenerator) Finalise() (error, io.Writer) {
|
||||
|
||||
}
|
||||
|
||||
type PkgIRGenerator struct {
|
||||
}
|
||||
|
||||
func NewPkgIRGenerator() PkgIRGenerator {
|
||||
return PkgIRGenerator{}
|
||||
}
|
||||
|
||||
func (p *PkgIRGenerator) Finalise() (error, io.Writer) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user