204 lines
5.9 KiB
Go
204 lines
5.9 KiB
Go
|
//go:generate npm --prefix frontend run build
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"embed"
|
||
|
"github.com/chi-middleware/logrus-logger"
|
||
|
"github.com/go-chi/chi/v5"
|
||
|
"github.com/go-chi/cors"
|
||
|
"github.com/go-chi/httprate"
|
||
|
log "github.com/sirupsen/logrus"
|
||
|
httpSwagger "github.com/swaggo/http-swagger"
|
||
|
"github.com/tdewolff/minify/v2"
|
||
|
"github.com/tdewolff/minify/v2/css"
|
||
|
"github.com/tdewolff/minify/v2/html"
|
||
|
"github.com/tdewolff/minify/v2/js"
|
||
|
"github.com/tdewolff/minify/v2/json"
|
||
|
"github.com/tdewolff/minify/v2/svg"
|
||
|
"github.com/tdewolff/minify/v2/xml"
|
||
|
"io"
|
||
|
"io/fs"
|
||
|
_ "minify.ccatss.dev/docs"
|
||
|
"net/http"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
//go:embed frontend/dist
|
||
|
frontendFs embed.FS
|
||
|
|
||
|
//go:embed LICENSE.txt
|
||
|
licenseBytes []byte
|
||
|
)
|
||
|
|
||
|
// @title Minifier API
|
||
|
// @version 1.0
|
||
|
// @description An API Implementation of tdewolfe's minify package
|
||
|
// @termsOfService http://swagger.io/terms/
|
||
|
|
||
|
// @contact.name ccatss
|
||
|
// @contact.url https://ccatss.dev
|
||
|
// @contact.email admin@meow.tf
|
||
|
|
||
|
// @license.name ISC License
|
||
|
// @license.url /LICENSE.txt
|
||
|
|
||
|
// @host minify.ccatss.dev
|
||
|
// @BasePath /api
|
||
|
func main() {
|
||
|
r := chi.NewRouter()
|
||
|
|
||
|
r.Use(logger.Logger("router", log.StandardLogger()))
|
||
|
|
||
|
m := minify.New()
|
||
|
m.AddFunc("text/css", css.Minify)
|
||
|
m.AddFunc("text/html", html.Minify)
|
||
|
m.AddFunc("image/svg+xml", svg.Minify)
|
||
|
m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
|
||
|
m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
|
||
|
m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)
|
||
|
|
||
|
subFs, err := fs.Sub(frontendFs, "frontend/dist")
|
||
|
|
||
|
if err != nil {
|
||
|
log.WithError(err).Fatalln("Unable to load frontend")
|
||
|
}
|
||
|
|
||
|
httpFs := http.FileServer(http.FS(subFs))
|
||
|
|
||
|
r.Handle("/", httpFs)
|
||
|
r.Handle("/js/*", httpFs)
|
||
|
r.Handle("/css/*", httpFs)
|
||
|
|
||
|
r.Get("/LICENSE.txt", func(w http.ResponseWriter, r *http.Request) {
|
||
|
w.Write(licenseBytes)
|
||
|
})
|
||
|
|
||
|
r.Get("/swagger/*", httpSwagger.Handler(
|
||
|
httpSwagger.URL("/swagger/doc.json"), //The url pointing to API definition
|
||
|
))
|
||
|
|
||
|
r.Route("/api", func(r chi.Router) {
|
||
|
r.Use(httprate.LimitByIP(100, 1*time.Minute))
|
||
|
|
||
|
r.Use(cors.Handler(cors.Options{
|
||
|
AllowedOrigins: []string{"https://*", "http://*"},
|
||
|
AllowedMethods: []string{"GET", "POST", "OPTIONS"},
|
||
|
AllowedHeaders: []string{"Accept", "Content-Type"},
|
||
|
ExposedHeaders: []string{"Link"},
|
||
|
AllowCredentials: false,
|
||
|
MaxAge: 300, // Maximum value not ignored by any of major browsers
|
||
|
}))
|
||
|
|
||
|
r.Post("/", minifyContent("", m))
|
||
|
r.Post("/css", minifyCss(m))
|
||
|
r.Post("/html", minifyHtml(m))
|
||
|
r.Post("/svg", minifySVG(m))
|
||
|
r.Post("/js", minifyJS(m))
|
||
|
r.Post("/json", minifyJSON(m))
|
||
|
r.Post("/xml", minifyXML(m))
|
||
|
})
|
||
|
|
||
|
http.ListenAndServe(":3000", r)
|
||
|
}
|
||
|
|
||
|
// Minify godoc
|
||
|
// @Summary Minify content
|
||
|
// @Description Minify content based on input type
|
||
|
// @Param input body string false "Input text"
|
||
|
// @Accept html,text/css,image/svg+xml,application/javascript,json,xml
|
||
|
// @Produce text/plain
|
||
|
// @Success 200 {string} string "Minified content"
|
||
|
// @Router / [post]
|
||
|
func minifyContent(mediaType string, min *minify.M) http.HandlerFunc {
|
||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||
|
if mediaType == "" {
|
||
|
mediaType = r.Header.Get("Content-Type")
|
||
|
|
||
|
if idx := strings.Index(mediaType, ";"); idx != -1 {
|
||
|
mediaType = mediaType[0:idx]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, err := io.Copy(w, min.Reader(mediaType, r.Body))
|
||
|
|
||
|
if err != nil {
|
||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Minify CSS godoc
|
||
|
// @Summary Minify CSS
|
||
|
// @Description Minify CSS Input
|
||
|
// @Param input body string false "Input CSS"
|
||
|
// @Accept text/css
|
||
|
// @Produce text/css
|
||
|
// @Success 200 {string} string "Minified CSS"
|
||
|
// @Router /css [post]
|
||
|
func minifyCss(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("text/css", min)
|
||
|
}
|
||
|
|
||
|
// Minify HTML godoc
|
||
|
// @Summary Minify HTML
|
||
|
// @Description Minify HTML Input
|
||
|
// @Param input body string false "Input HTML"
|
||
|
// @Accept html
|
||
|
// @Produce html
|
||
|
// @Success 200 {string} string "Minified HTML"
|
||
|
// @Router /html [post]
|
||
|
func minifyHtml(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("text/html", min)
|
||
|
}
|
||
|
|
||
|
// Minify SVG godoc
|
||
|
// @Summary Minify SVG
|
||
|
// @Description Minify SVG Input
|
||
|
// @Param input body string false "Input SVG"
|
||
|
// @Accept image/svg+xml
|
||
|
// @Produce image/svg+xml
|
||
|
// @Success 200 {string} string "Minified SVG"
|
||
|
// @Router /svg [post]
|
||
|
func minifySVG(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("image/svg+xml", min)
|
||
|
}
|
||
|
|
||
|
// Minify JS godoc
|
||
|
// @Summary Minify JavaScript
|
||
|
// @Description Minify JavaScript Input
|
||
|
// @Param input body string false "Input JavaScript"
|
||
|
// @Accept application/javascript
|
||
|
// @Produce application/javascript
|
||
|
// @Success 200 {string} string "Minified JavaScript"
|
||
|
// @Router /js [post]
|
||
|
func minifyJS(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("application/javascript", min)
|
||
|
}
|
||
|
|
||
|
// Minify JSON godoc
|
||
|
// @Summary Minify JSON
|
||
|
// @Description Minify JSON Input
|
||
|
// @Param input body string false "Input JSON"
|
||
|
// @Accept application/json
|
||
|
// @Produce application/json
|
||
|
// @Success 200 {string} string "Minified JSON"
|
||
|
// @Router /json [post]
|
||
|
func minifyJSON(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("application/json", min)
|
||
|
}
|
||
|
|
||
|
// Minify XML godoc
|
||
|
// @Summary Minify XML
|
||
|
// @Description Minify XML Input
|
||
|
// @Param input body string false "Input XML"
|
||
|
// @Accept xml
|
||
|
// @Produce xml
|
||
|
// @Success 200 {string} string "Minified XML"
|
||
|
// @Router /xml [post]
|
||
|
func minifyXML(min *minify.M) http.HandlerFunc {
|
||
|
return minifyContent("text/xml", min)
|
||
|
}
|