refactor: merge flowchartsman/swaggerui into our own code base to simplify routing
This commit is contained in:
parent
69ae351d94
commit
279cc484fc
|
@ -0,0 +1,139 @@
|
||||||
|
// This program downloads the dist assets for the current swagger-ui version and places them into the embed directory
|
||||||
|
// TODO: Compress?
|
||||||
|
|
||||||
|
//go:build ignore
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type releaseResp []struct {
|
||||||
|
// TagName is a release tag name
|
||||||
|
TagName string `json:"tag_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
releases := releaseResp{}
|
||||||
|
// get the releases so we can download the latest one
|
||||||
|
req, _ := http.NewRequest("GET", "https://api.github.com/repos/swagger-api/swagger-ui/releases", nil)
|
||||||
|
req.Header.Set("Accept", "application/vnd.github.v3+json")
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error getting release list: %v", err)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.Fatalf("got status [%s] on release list download", resp.Status)
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&releases); err != nil {
|
||||||
|
log.Fatalf("error decoding response: %v", err)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
if len(releases) == 0 {
|
||||||
|
log.Fatal("somehow got no releases, nothing to do")
|
||||||
|
}
|
||||||
|
tag := releases[0].TagName
|
||||||
|
|
||||||
|
current, err := ioutil.ReadFile("current_version.txt")
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, fs.ErrNotExist):
|
||||||
|
// no problem, just do it
|
||||||
|
default:
|
||||||
|
log.Fatalf("unable to check version in current_version.txt: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cv := string(bytes.TrimRight(current, "\n"))
|
||||||
|
|
||||||
|
if cv == tag {
|
||||||
|
log.Print("version is current, nothing to do")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("downloading release %s...", tag)
|
||||||
|
|
||||||
|
resp, err = http.Get(fmt.Sprintf("https://github.com/swagger-api/swagger-ui/archive/%s.tar.gz", tag))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error downloading release archive: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.Fatalf("got status [%s] on release archive download", resp.Status)
|
||||||
|
}
|
||||||
|
zr, err := gzip.NewReader(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error opening file as gzip: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll("embed"); err != nil {
|
||||||
|
log.Fatalf("error removing old embed directory")
|
||||||
|
}
|
||||||
|
if err := os.Mkdir("embed", 0o700); err != nil {
|
||||||
|
log.Fatalf("error recreating embed directory")
|
||||||
|
}
|
||||||
|
tr := tar.NewReader(zr)
|
||||||
|
for {
|
||||||
|
header, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("tar parsing error: %v", err)
|
||||||
|
}
|
||||||
|
if header.Typeflag == tar.TypeReg {
|
||||||
|
// got a file, remove version directory
|
||||||
|
fname := header.Name[strings.Index(header.Name, `/`):]
|
||||||
|
if strings.HasPrefix(fname, `/dist`) {
|
||||||
|
fname = strings.TrimPrefix(fname, `/dist`)
|
||||||
|
out, err := os.Create(filepath.Join("embed", fname))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error create output file: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(out, tr); err != nil {
|
||||||
|
log.Fatalf("error writing output file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// replace the hard-coded JSON file with a generic file and disable the topbar
|
||||||
|
initFile, err := os.ReadFile(filepath.Join("embed", "swagger-initializer.js"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error opening swagger-initializer.js for templating :%v", err)
|
||||||
|
}
|
||||||
|
newInit := regexp.MustCompile(`url:\s+"[^"]*"`).ReplaceAllLiteral(initFile, []byte(`url: "./swagger_spec"`))
|
||||||
|
newInit = regexp.MustCompile(`,?\s+SwaggerUIStandalonePreset.*\n`).ReplaceAllLiteral(newInit, []byte("\n"))
|
||||||
|
newInit = regexp.MustCompile(`(?s),\s+plugins: \[.*],\n`).ReplaceAllLiteral(newInit, []byte("\n"))
|
||||||
|
newInit = regexp.MustCompile(`\n\s*layout:.*\n`).ReplaceAllLiteral(newInit, []byte("\n"))
|
||||||
|
//fmt.Println(string(newInit))
|
||||||
|
newinitFile, err := os.Create(filepath.Join("embed", "swagger-initializer.js"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error re-creating swagger-initializer.js file: %v", err)
|
||||||
|
}
|
||||||
|
defer newinitFile.Close()
|
||||||
|
if _, err := newinitFile.Write(newInit); err != nil {
|
||||||
|
log.Fatalf("unable to write to swagger-initializer.js: %v", err)
|
||||||
|
}
|
||||||
|
newcv, err := os.Create("current_version.txt")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("can't update current_version.txt: %v", err)
|
||||||
|
}
|
||||||
|
defer newcv.Close()
|
||||||
|
newcv.WriteString(tag)
|
||||||
|
log.Printf("updated swaggerui from %s => %s, please check templated swagger-initializer.js and retag repo", cv, tag)
|
||||||
|
}
|
26
api/s5/s5.go
26
api/s5/s5.go
|
@ -3,6 +3,7 @@ package s5
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
"embed"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.lumeweb.com/LumeWeb/portal/account"
|
"git.lumeweb.com/LumeWeb/portal/account"
|
||||||
|
@ -11,12 +12,12 @@ import (
|
||||||
protoRegistry "git.lumeweb.com/LumeWeb/portal/protocols/registry"
|
protoRegistry "git.lumeweb.com/LumeWeb/portal/protocols/registry"
|
||||||
"git.lumeweb.com/LumeWeb/portal/protocols/s5"
|
"git.lumeweb.com/LumeWeb/portal/protocols/s5"
|
||||||
"git.lumeweb.com/LumeWeb/portal/storage"
|
"git.lumeweb.com/LumeWeb/portal/storage"
|
||||||
"github.com/flowchartsman/swaggerui"
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
"github.com/getkin/kin-openapi/openapi3"
|
||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.sia.tech/jape"
|
"go.sia.tech/jape"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
@ -28,6 +29,11 @@ var (
|
||||||
//go:embed swagger.yaml
|
//go:embed swagger.yaml
|
||||||
var spec []byte
|
var spec []byte
|
||||||
|
|
||||||
|
//go:generate go run generate.go
|
||||||
|
|
||||||
|
//go:embed embed
|
||||||
|
var swagfs embed.FS
|
||||||
|
|
||||||
type S5API struct {
|
type S5API struct {
|
||||||
config *viper.Viper
|
config *viper.Viper
|
||||||
identity ed25519.PrivateKey
|
identity ed25519.PrivateKey
|
||||||
|
@ -104,6 +110,12 @@ func (s S5API) Stop(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func byteHandler(b []byte) jape.Handler {
|
||||||
|
return func(c jape.Context) {
|
||||||
|
c.ResponseWriter.Write(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getRoutes(s *S5API) map[string]jape.Handler {
|
func getRoutes(s *S5API) map[string]jape.Handler {
|
||||||
tusHandler := BuildS5TusApi(s.identity, s.accounts, s.storage)
|
tusHandler := BuildS5TusApi(s.identity, s.accounts, s.storage)
|
||||||
|
|
||||||
|
@ -131,12 +143,10 @@ func getRoutes(s *S5API) map[string]jape.Handler {
|
||||||
|
|
||||||
wrappedTusHandler := middleware.ApplyMiddlewares(tusOptionsHandler, tusCors, middleware.AuthMiddleware(s.identity, s.accounts))
|
wrappedTusHandler := middleware.ApplyMiddlewares(tusOptionsHandler, tusCors, middleware.AuthMiddleware(s.identity, s.accounts))
|
||||||
|
|
||||||
|
swaggerFiles, _ := fs.Sub(swagfs, "embed")
|
||||||
|
swaggerServ := http.FileServer(http.FS(swaggerFiles))
|
||||||
swaggerHandler := func(c jape.Context) {
|
swaggerHandler := func(c jape.Context) {
|
||||||
swaggerui.Handler(jsonDoc).ServeHTTP(c.ResponseWriter, c.Request)
|
swaggerServ.ServeHTTP(c.ResponseWriter, c.Request)
|
||||||
}
|
|
||||||
|
|
||||||
swaggerStripPrefix := func(h http.Handler) http.Handler {
|
|
||||||
return http.StripPrefix("/swagger", h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]jape.Handler{
|
return map[string]jape.Handler{
|
||||||
|
@ -180,8 +190,8 @@ func getRoutes(s *S5API) map[string]jape.Handler {
|
||||||
"POST /s5/registry": middleware.ApplyMiddlewares(s.httpHandler.RegistrySet, middleware.AuthMiddleware(s.identity, s.accounts)),
|
"POST /s5/registry": middleware.ApplyMiddlewares(s.httpHandler.RegistrySet, middleware.AuthMiddleware(s.identity, s.accounts)),
|
||||||
"GET /s5/registry/subscription": middleware.ApplyMiddlewares(s.httpHandler.RegistrySubscription, middleware.AuthMiddleware(s.identity, s.accounts)),
|
"GET /s5/registry/subscription": middleware.ApplyMiddlewares(s.httpHandler.RegistrySubscription, middleware.AuthMiddleware(s.identity, s.accounts)),
|
||||||
|
|
||||||
"GET /swagger": middleware.ApplyMiddlewares(swaggerHandler, middleware.AdaptMiddleware(swaggerStripPrefix)),
|
"GET /swagger/swagger_spec": middleware.ApplyMiddlewares(byteHandler(jsonDoc)),
|
||||||
"GET /swagger/swagger_spec": middleware.ApplyMiddlewares(swaggerHandler, middleware.AdaptMiddleware(swaggerStripPrefix)),
|
"GET /swagger": middleware.ApplyMiddlewares(swaggerHandler),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue