first version

This commit is contained in:
Jay
2021-09-16 10:19:48 +08:00
commit 05967cdb98
24 changed files with 1669 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
package server
import (
"context"
"fmt"
"net/http"
"os"
"rpirelay/config"
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
type Server struct {
*gin.Engine
cfg *config.Config
}
func New(cfg *config.Config) *Server {
e := gin.New()
e.Use(gin.Logger())
e.Use(gin.Recovery())
corsCfg := cors.DefaultConfig()
corsCfg.AllowOriginFunc = func(origin string) bool { return origin != "" }
corsCfg.AllowCredentials = true
corsCfg.AddAllowHeaders("Authorization")
e.Use(cors.New(corsCfg))
if os.Getenv("RELEASE") != "1" {
e.Use(SwaggerServe("/api-docs", nil))
e.GET("/api-docs.json", SwaggerSpecServe())
}
// set healthcheck path
e.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "ok")
})
return &Server{
Engine: e,
cfg: cfg,
}
}
func (w *Server) Start(ctx context.Context) {
s := &http.Server{
Handler: w,
Addr: fmt.Sprintf(":%d", w.cfg.Server.Port),
}
go func() {
if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
s.ErrorLog.Fatal(err)
}
}()
<-ctx.Done()
c, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if err := s.Shutdown(c); err != nil {
s.ErrorLog.Fatal(err)
}
}
+81
View File
@@ -0,0 +1,81 @@
package server
import (
"encoding/json"
"fmt"
"net/http"
"net/textproto"
"regexp"
rpiRelay "rpirelay"
"strings"
"github.com/gin-gonic/gin"
)
type SwaggerOptions struct {
Root string
}
var regex = regexp.MustCompile(`(src|href)="./`)
var specRegex = regexp.MustCompile(`url:.+`)
func SwaggerSpecServe() gin.HandlerFunc {
return func(c *gin.Context) {
b := rpiRelay.GetSpec()
var j map[string]interface{}
if err := json.Unmarshal(b, &j); err != nil {
c.String(http.StatusInternalServerError, "internal error")
return
}
if _, ok := j["host"]; ok {
j["host"] = c.Request.Host
}
if xfp := c.Request.Header.Get(textproto.CanonicalMIMEHeaderKey("X-Forwarded-Proto")); xfp != "" && xfp == "https" {
j["schemes"] = []string{xfp}
}
c.JSON(http.StatusOK, j)
}
}
func SwaggerServe(prefix string, opts *SwaggerOptions) gin.HandlerFunc {
return func(c *gin.Context) {
fp := c.Request.URL.Path
if prefix != "" {
if !strings.HasPrefix(fp, prefix) {
c.Next()
return
}
if fp = strings.Replace(fp, prefix, "", 1); fp == "" {
fp = "/"
}
}
// end of slash replace to index.html file
if strings.HasSuffix(fp, "/") {
fp += "index.html"
}
if b, mime, err := rpiRelay.GetWebFile(fp); err == nil {
// 如果是 index.html 要更新內部的連結 轉換成絕對路徑
if fp == "/index.html" {
replPrefix := prefix
if !strings.HasSuffix(replPrefix, "/") {
replPrefix += "/"
}
b = regex.ReplaceAll(b, []byte(fmt.Sprintf(`$1="%s`, replPrefix)))
b = specRegex.ReplaceAll(b, []byte(fmt.Sprintf(`url: "%s.json",`, prefix)))
}
c.Writer.Header().Set(textproto.CanonicalMIMEHeaderKey("Content-Type"), mime)
c.Status(http.StatusOK)
c.Writer.Write(b)
c.Abort()
}
}
}