dashboard/controller/unisc/httproute.go

183 lines
3.9 KiB
Go

package unisc
import (
"bytes"
"dashboard/dao/sqldb"
"dashboard/models"
"dashboard/routes"
"dashboard/services/uniss"
"dashboard/utils"
"io"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
type HttpRoute struct {
httpHandle *httpHandle
middleWare *middleWare
}
type UnisHttpChanneler interface {
GetHttpChannel() chan *models.UnisHttpRequest
}
func NewHttpRoute(httpc ...UnisHttpChanneler) *HttpRoute {
res := new(HttpRoute)
var httpC []chan *models.UnisHttpRequest
for _, cha := range httpc {
httpC = append(httpC, cha.GetHttpChannel())
}
res.httpHandle = newhttpHandle(httpC)
res.middleWare = newmiddleWare()
return res
}
func (u *HttpRoute) AddRoute(r *gin.Engine) {
unisr := r.Group(models.UnisHttpUrlPrefix)
unisr.Use(routes.ErrWapper(u.middleWare.ginCheckServerId), routes.ErrWapper(u.middleWare.ginStoreRequest))
{
unisr.POST(models.UNIS_HTTP_URL_CONFIG_ADD.Url(), routes.ErrWapper(u.httpHandle.stationConfig))
}
}
type middleWare struct {
}
func newmiddleWare() *middleWare {
return new(middleWare)
}
func (m *middleWare) ginCheckServerId(c *gin.Context) error {
serverId := c.GetHeader("serverId")
if serverId != serverId {
c.Abort()
return &models.BaseError{
Code: http.StatusServiceUnavailable,
Msg: "Server Id error",
}
}
channel, err := strconv.Atoi(c.GetHeader("channel"))
if err != nil {
c.Abort()
return &models.BaseError{
Code: http.StatusServiceUnavailable,
Msg: "Channel Id error",
}
}
c.Set(models.GinContextServerId, serverId)
c.Set(models.GinContextChannel, channel)
c.Next()
return nil
}
// bodyLogWriter 自定义响应写入器,用于捕获响应体
type bodyLogWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
// Write 实现写入接口,同时写入缓冲区和原始响应
func (w *bodyLogWriter) Write(b []byte) (int, error) {
w.body.Write(b)
return w.ResponseWriter.Write(b)
}
// WriteString 实现字符串写入接口(优化性能)
func (w *bodyLogWriter) WriteString(s string) (int, error) {
w.body.WriteString(s)
return w.ResponseWriter.WriteString(s)
}
func (m *middleWare) ginStoreRequest(c *gin.Context) (err error) {
defer func() {
if err != nil {
c.Abort()
return
}
}()
log, _ := utils.GetLogFromContext(c)
channel := c.GetInt(models.GinContextChannel)
oldConf, _err := sqldb.ResFulDataGet(c.Request.Method, c.Request.URL.String(), channel)
if _err != nil {
err = _err
return
}
bodyBytes, _err := io.ReadAll(c.Request.Body)
if _err != nil {
err = _err
return
}
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
// 创建自定义响应写入器
blw := &bodyLogWriter{
body: bytes.NewBufferString(""),
ResponseWriter: c.Writer,
}
c.Writer = blw
c.Next()
// 获取响应信息
// statusCode := c.Writer.Status()
responseBody := blw.body.String()
// // 安全日志记录:限制大响应体
// logBody := responseBody
// if len(responseBody) > 1000 {
// logBody = responseBody[:1000] + "...[TRUNCATED]"
// }
if oldConf != string(bodyBytes) {
log.Sugar().Info("The resful request is not equel local store so will save to database...")
if _err := sqldb.ResFulDataStore(c.Request.Method, c.Request.URL.String(), responseBody, string(bodyBytes), channel); _err != nil {
err = _err
}
}
return nil
}
func (m *middleWare) ginWithUnisObject(unis *uniss.UnisStation) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(models.GinContextUnis, unis)
c.Next()
}
}
func (m *middleWare) getUnisObjectFromContext(c *gin.Context) (*uniss.UnisStation, error) {
res, ok := c.Get(models.GinContextUnis)
if !ok {
return nil, models.ErrorInvalidData
}
unis, ok := res.(*uniss.UnisStation)
if !ok {
return nil, models.ErrorInvalidData
}
return unis, nil
}
func (m *middleWare) ginWithExpireTime(expire time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(models.GinContextExpire, expire)
c.Next()
}
}