dashboard/routes/routes.go

185 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package routes
import (
"context"
"dashboard/controller"
"dashboard/logger"
"dashboard/pkg/jwt"
"dashboard/settings"
"errors"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
)
type Router struct {
r *gin.Engine
addr string
log *logger.Logger
}
type AddRouter interface {
AddRoute(*gin.Engine)
}
func NewRouter(addr string, log *logger.Logger, rate settings.RateLimitConfig, jwtC settings.JwtConfig, routes ...AddRouter) *Router {
cjwt := jwt.New(jwt.WithSalt(jwtC.Salt), jwt.WithExpire(time.Duration(jwtC.Expire)*time.Second))
r := gin.New()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Origin", "Content-Type"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.Use(GinLogger(log), GinRecovery(log, true), GinLog(log), ErrWapper(GinRateLimit(rate)))
// 静态文件服务
r.Static("/static", "./static")
r.StaticFile("/", "./static/index.html")
r.GET("login", controller.LoginPage)
r.POST("/api/login", ErrWapper(controller.UserSignInHandler(cjwt)))
r.POST("/api/logout", controller.UserLogOutHandler)
g1 := r.Group("/api")
g1.Use(ErrWapper(GinJwtAuthor(cjwt)))
{
g1.GET("/system-info", ErrWapper(controller.SystemInfoHandle))
g1.POST("/upload", ErrWapper(controller.FileUploadHandle))
g1.GET("/files", ErrWapper(controller.FileListHandle))
g1.GET("/download", ErrWapper(controller.FileDownloadHandle))
}
r.GET("/ws/terminal", ErrWapper(GinJwtAuthor(cjwt)), ErrWapper(controller.TerminalHandle()))
for _, route := range routes {
route.AddRoute(r)
}
pprof.Register(r)
return &Router{
r: r,
addr: addr,
log: log,
}
}
func (r *Router) Run(ctx context.Context) error {
srv := &http.Server{
Addr: r.addr,
Handler: r.r,
}
r.log.Sugar().Infof("Server listen on %s", r.addr)
wg, ctx := errgroup.WithContext(ctx)
wg.Go(func() error {
// 开启一个goroutine启动服务
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
r.log.Error("listen: %s\n", zap.Error(err))
return err
}
return nil
})
wg.Go(func() error {
// 等待中断信号来优雅地关闭服务器为关闭服务器操作设置一个5秒的超时
quit := make(chan os.Signal, 1) // 创建一个接收信号的通道
// kill 默认会发送 syscall.SIGTERM 信号
// kill -2 发送 syscall.SIGINT 信号我们常用的Ctrl+C就是触发系统SIGINT信号
// kill -9 发送 syscall.SIGKILL 信号,但是不能被捕获,所以不需要添加它
// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信号转发给quit
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞
select {
case <-ctx.Done():
r.log.Error("Http Server Cancel by ctx")
case <-quit:
}
// 阻塞在此,当接收到上述两种信号时才会往下执行
r.log.Info("Shutdown Server ...")
// 创建一个5秒超时的context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 5秒内优雅关闭服务将未处理完的请求处理完再关闭服务超过5秒就超时退出
if err := srv.Shutdown(ctx); err != nil {
r.log.Error("Server Shutdown: ", zap.Error(err))
return err
}
r.log.Info("Server exiting")
return errors.New("Server Shutdown")
})
if err := wg.Wait(); err != nil {
return err
}
return nil
}
/*
func Setup(log *logger.Logger, rate settings.RateLimitConfig, jwtC settings.JwtConfig) *gin.Engine {
cjwt := jwt.New(jwt.WithSalt(jwtC.Salt), jwt.WithExpire(time.Duration(jwtC.Expire)*time.Second))
r := gin.New()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Origin", "Content-Type"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.Use(GinLogger(log), GinRecovery(log, true), GinLog(log), errWapper(GinRateLimit(rate)))
// 静态文件服务
r.Static("/static", "./static")
r.StaticFile("/", "./static/index.html")
r.GET("login", controller.LoginPage)
r.POST("/api/login", errWapper(controller.UserSignInHandler(cjwt)))
r.POST("/api/logout", controller.UserLogOutHandler)
g1 := r.Group("/api")
g1.Use(errWapper(GinJwtAuthor(cjwt)))
{
g1.GET("/system-info", errWapper(controller.SystemInfoHandle))
g1.POST("/upload", errWapper(controller.FileUploadHandle))
g1.GET("/files", errWapper(controller.FileListHandle))
g1.GET("/download", errWapper(controller.FileDownloadHandle))
}
r.GET("/ws/terminal", errWapper(GinJwtAuthor(cjwt)), errWapper(controller.TerminalHandle()))
// unisr := r.Group("/api/unis")
// unisr.Use(errWapper(GinCheckServerId), errWapper(GinStoreRequest))
// {
// unisr.POST("/config/v1/add", errWapper(unis.StationConfig))
// }
return r
}
*/