diff --git a/.air.toml b/.air.toml index 85b798bc..c69808de 100644 --- a/.air.toml +++ b/.air.toml @@ -7,7 +7,7 @@ tmp_dir = "tmp" [build] # Just plain old shell command. You could use `make` as well. -cmd = "go build -o ./tmp/main ." +cmd = "go build -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/server/settings.BuildTime=$(date +%Y.%m.%d.%H%M%S)'\" -o ./tmp/main ." # Binary file yields from `cmd`. bin = "tmp/main" # Customize binary. @@ -50,4 +50,4 @@ runner = "green" [misc] # Delete tmp directory on exit -clean_on_exit = true \ No newline at end of file +clean_on_exit = true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43181ba9..a89fa506 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - name: Build run: | mkdir -p dist - go build -ldflags "$LD_FLAGS" -o dist/nginx-ui -v main.go + go build -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/server/settings.BuildTime=$(date +%Y.%m.%d.%H%M%S)'" -o dist/nginx-ui -v main.go - name: Archive backend artifacts uses: actions/upload-artifact@v2 diff --git a/server/router/middleware.go b/server/router/middleware.go index e1d535fb..66e6d55a 100644 --- a/server/router/middleware.go +++ b/server/router/middleware.go @@ -4,14 +4,29 @@ import ( "encoding/base64" "github.com/0xJacky/Nginx-UI/frontend" "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/settings" "github.com/gin-contrib/static" "github.com/gin-gonic/gin" "io/fs" "log" "net/http" "path" + "strings" + "time" ) +func recovery() gin.HandlerFunc { + return func(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + log.Println(err) + } + }() + + c.Next() + } +} + func authRequired() gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("Authorization") @@ -64,3 +79,18 @@ func mustFS(dir string) (serverFileSystem static.ServeFileSystem) { return } + +func cacheJs() gin.HandlerFunc { + return func(c *gin.Context) { + if strings.Contains(c.Request.URL.String(), "js") { + c.Header("Cache-Control", "max-age: 1296000") + t, _ := time.Parse("2006.01.02.150405", settings.BuildTime) + t = t.Add(-8 * time.Hour) + lastModified := strings.ReplaceAll(t.Format(time.RFC1123), "UTC", "GMT") + if c.Request.Header.Get("If-Modified-Since") == lastModified { + c.AbortWithStatus(http.StatusNotModified) + } + c.Header("Last-Modified", lastModified) + } + } +} diff --git a/server/router/routers.go b/server/router/routers.go index 080b69a8..b302ef51 100644 --- a/server/router/routers.go +++ b/server/router/routers.go @@ -1,85 +1,87 @@ package router import ( - "bufio" - "github.com/0xJacky/Nginx-UI/server/api" - "github.com/0xJacky/Nginx-UI/server/settings" - "github.com/gin-contrib/static" - "github.com/gin-gonic/gin" - "net/http" - "strings" + "bufio" + "github.com/0xJacky/Nginx-UI/server/api" + "github.com/0xJacky/Nginx-UI/server/settings" + "github.com/gin-contrib/static" + "github.com/gin-gonic/gin" + "net/http" + "strings" ) func InitRouter() *gin.Engine { - r := gin.New() - r.Use(gin.Logger()) + r := gin.New() + r.Use(gin.Logger()) - r.Use(gin.Recovery()) + r.Use(recovery()) - r.Use(static.Serve("/", mustFS(""))) + r.Use(cacheJs()) - r.NoRoute(func(c *gin.Context) { - accept := c.Request.Header.Get("Accept") - if strings.Contains(accept, "text/html") { - file, _ := mustFS("").Open("index.html") - stat, _ := file.Stat() - c.DataFromReader(http.StatusOK, stat.Size(), "text/html", - bufio.NewReader(file), nil) - } - }) + r.Use(static.Serve("/", mustFS(""))) - g := r.Group("/api") - { + r.NoRoute(func(c *gin.Context) { + accept := c.Request.Header.Get("Accept") + if strings.Contains(accept, "text/html") { + file, _ := mustFS("").Open("index.html") + stat, _ := file.Stat() + c.DataFromReader(http.StatusOK, stat.Size(), "text/html", + bufio.NewReader(file), nil) + } + }) - g.GET("settings", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "demo": settings.ServerSettings.Demo, - }) - }) + g := r.Group("/api") + { - g.GET("install", api.InstallLockCheck) - g.POST("install", api.InstallNginxUI) + g.GET("settings", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "demo": settings.ServerSettings.Demo, + }) + }) - g.POST("/login", api.Login) - g.DELETE("/logout", api.Logout) + g.GET("install", api.InstallLockCheck) + g.POST("install", api.InstallNginxUI) - g := g.Group("/", authRequired()) - { - g.GET("/analytic", api.Analytic) - g.GET("/analytic/init", api.GetAnalyticInit) + g.POST("/login", api.Login) + g.DELETE("/logout", api.Logout) - g.GET("/users", api.GetUsers) - g.GET("/user/:id", api.GetUser) - g.POST("/user", api.AddUser) - g.POST("/user/:id", api.EditUser) - g.DELETE("/user/:id", api.DeleteUser) + g := g.Group("/", authRequired()) + { + g.GET("/analytic", api.Analytic) + g.GET("/analytic/init", api.GetAnalyticInit) - g.GET("domains", api.GetDomains) - g.GET("domain/:name", api.GetDomain) - g.POST("domain/:name", api.EditDomain) - g.POST("domain/:name/enable", api.EnableDomain) - g.POST("domain/:name/disable", api.DisableDomain) - g.DELETE("domain/:name", api.DeleteDomain) + g.GET("/users", api.GetUsers) + g.GET("/user/:id", api.GetUser) + g.POST("/user", api.AddUser) + g.POST("/user/:id", api.EditUser) + g.DELETE("/user/:id", api.DeleteUser) - g.GET("configs", api.GetConfigs) - g.GET("config/:name", api.GetConfig) - g.POST("config", api.AddConfig) - g.POST("config/:name", api.EditConfig) + g.GET("domains", api.GetDomains) + g.GET("domain/:name", api.GetDomain) + g.POST("domain/:name", api.EditDomain) + g.POST("domain/:name/enable", api.EnableDomain) + g.POST("domain/:name/disable", api.DisableDomain) + g.DELETE("domain/:name", api.DeleteDomain) - g.GET("backups", api.GetFileBackupList) - g.GET("backup/:id", api.GetFileBackup) + g.GET("configs", api.GetConfigs) + g.GET("config/:name", api.GetConfig) + g.POST("config", api.AddConfig) + g.POST("config/:name", api.EditConfig) - g.GET("template/:name", api.GetTemplate) + g.GET("backups", api.GetFileBackupList) + g.GET("backup/:id", api.GetFileBackup) - g.GET("cert/issue/:domain", api.IssueCert) - g.GET("cert/:domain/info", api.CertInfo) + g.GET("template/:name", api.GetTemplate) - // 添加域名到自动续期列表 - g.POST("cert/:domain", api.AddDomainToAutoCert) - // 从自动续期列表中删除域名 - g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert) - } - } + g.GET("cert/issue/:domain", api.IssueCert) + g.GET("cert/:domain/info", api.CertInfo) - return r + // 添加域名到自动续期列表 + g.POST("cert/:domain", api.AddDomainToAutoCert) + // 从自动续期列表中删除域名 + g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert) + } + } + + return r } diff --git a/server/settings/settings.go b/server/settings/settings.go index b9eb368d..ce5b564a 100644 --- a/server/settings/settings.go +++ b/server/settings/settings.go @@ -7,6 +7,10 @@ import ( var Conf *ini.File +var ( + BuildTime string +) + type Server struct { HttpPort string RunMode string