219 lines
4.6 KiB
Go
219 lines
4.6 KiB
Go
package unisc
|
|
|
|
import (
|
|
"bytes"
|
|
"dashboard/dao/sqldb"
|
|
"dashboard/models"
|
|
"dashboard/routes"
|
|
"dashboard/services/uniss"
|
|
"dashboard/utils"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type HttpRoute struct {
|
|
httpHandle *httpHandle
|
|
middleWare *middleWare
|
|
}
|
|
|
|
type UnisHttpChanneler interface {
|
|
GetHttpServerChannel() chan *models.UnisHttpRequest
|
|
}
|
|
|
|
func NewHttpRoute(httpc ...UnisHttpChanneler) *HttpRoute {
|
|
res := new(HttpRoute)
|
|
|
|
var httpC []chan *models.UnisHttpRequest
|
|
for _, cha := range httpc {
|
|
httpC = append(httpC, cha.GetHttpServerChannel())
|
|
}
|
|
|
|
res.httpHandle = newhttpHandle(httpC)
|
|
res.middleWare = newmiddleWare()
|
|
|
|
return res
|
|
}
|
|
|
|
func (u *HttpRoute) AddRoute(r *gin.Engine) {
|
|
unis := r.Group(models.UnisHttpUrlPrefix)
|
|
unis.Use(routes.ErrWapper(u.middleWare.ginCheckServerId), routes.ErrWapper(u.middleWare.ginStoreRequest), u.middleWare.ginSetUnisHttpContext)
|
|
{
|
|
unis.POST(models.UNIS_HTTP_URL_CONFIG_ADD.URL(), routes.ErrWapper(u.httpHandle.stationConfig))
|
|
}
|
|
}
|
|
|
|
type middleWare struct {
|
|
pool sync.Pool
|
|
}
|
|
|
|
func newmiddleWare() *middleWare {
|
|
res := new(middleWare)
|
|
|
|
res.pool.New = func() any { return createUnisHttpRequest() }
|
|
|
|
return res
|
|
}
|
|
|
|
func createUnisHttpRequest() *models.UnisHttpRequest {
|
|
res := new(models.UnisHttpRequest)
|
|
|
|
res.ResC = make(chan *models.UnisHttpResponse)
|
|
res.ResP = new(models.UnisHttpResponse)
|
|
|
|
return res
|
|
}
|
|
|
|
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 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()
|
|
}
|
|
}
|
|
|
|
func (m *middleWare) ginSetUnisHttpContext(c *gin.Context) {
|
|
req := m.pool.Get()
|
|
c.Set(models.GinContextUnisHttpReq, req)
|
|
c.Next()
|
|
m.pool.Put(req)
|
|
}
|
|
|
|
func getUnisHttpContextFromContext(c *gin.Context) (*models.UnisHttpRequest, error) {
|
|
res, ok := c.Get(models.GinContextUnisHttpReq)
|
|
if !ok {
|
|
return nil, models.ErrorInvalidData
|
|
}
|
|
|
|
unis, ok := res.(*models.UnisHttpRequest)
|
|
if !ok {
|
|
return nil, models.ErrorInvalidData
|
|
}
|
|
|
|
return unis, nil
|
|
}
|