chat_ws_controller.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package llm
  2. import (
  3. "eta/eta_api/controllers"
  4. "eta/eta_api/models"
  5. "eta/eta_api/models/system"
  6. "eta/eta_api/services/llm/facade"
  7. "eta/eta_api/utils"
  8. "eta/eta_api/utils/ws"
  9. "fmt"
  10. "github.com/gorilla/websocket"
  11. "net"
  12. "net/http"
  13. "strings"
  14. "time"
  15. )
  16. type ChatWsController struct {
  17. controllers.BaseAuthController
  18. }
  19. func (cc *ChatWsController) Prepare() {
  20. method := cc.Ctx.Input.Method()
  21. uri := cc.Ctx.Input.URI()
  22. if method == "GET" {
  23. authorization := cc.Ctx.Input.Header("authorization")
  24. if authorization == "" {
  25. authorization = cc.Ctx.Input.Header("Authorization")
  26. }
  27. if strings.Contains(authorization, ";") {
  28. authorization = strings.Replace(authorization, ";", "$", 1)
  29. }
  30. if authorization == "" {
  31. strArr := strings.Split(uri, "?")
  32. for k, v := range strArr {
  33. fmt.Println(k, v)
  34. }
  35. if len(strArr) > 1 {
  36. authorization = strArr[1]
  37. authorization = strings.Replace(authorization, "Authorization", "authorization", -1)
  38. }
  39. }
  40. if authorization == "" {
  41. utils.FileLog.Error("authorization为空,未授权")
  42. cc.Ctx.ResponseWriter.WriteHeader(http.StatusUnauthorized)
  43. return
  44. }
  45. tokenStr := authorization
  46. tokenArr := strings.Split(tokenStr, "=")
  47. token := tokenArr[1]
  48. session, err := system.GetSysSessionByToken(token)
  49. if err != nil {
  50. if utils.IsErrNoRow(err) {
  51. utils.FileLog.Error("authorization已过期")
  52. cc.Ctx.ResponseWriter.WriteHeader(http.StatusUnauthorized)
  53. return
  54. }
  55. utils.FileLog.Error("authorization查询用户信息失败")
  56. cc.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
  57. return
  58. }
  59. if session == nil {
  60. utils.FileLog.Error("会话不存在")
  61. cc.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
  62. return
  63. }
  64. //校验token是否合法
  65. // JWT校验Token和Account
  66. account := utils.MD5(session.UserName)
  67. if !utils.CheckToken(account, token) {
  68. utils.FileLog.Error("authorization校验不合法")
  69. cc.Ctx.ResponseWriter.WriteHeader(http.StatusUnauthorized)
  70. return
  71. }
  72. if time.Now().After(session.ExpiredTime) {
  73. utils.FileLog.Error("authorization过期法")
  74. cc.Ctx.ResponseWriter.WriteHeader(http.StatusUnauthorized)
  75. return
  76. }
  77. admin, err := system.GetSysUserById(session.SysUserId)
  78. if err != nil {
  79. if utils.IsErrNoRow(err) {
  80. utils.FileLog.Error("权限不够")
  81. cc.Ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
  82. return
  83. }
  84. utils.FileLog.Error("获取用户信息失败")
  85. cc.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
  86. return
  87. }
  88. if admin == nil {
  89. utils.FileLog.Error("权限不够")
  90. cc.Ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
  91. return
  92. }
  93. //如果不是启用状态
  94. if admin.Enabled != 1 {
  95. utils.FileLog.Error("用户被禁用")
  96. cc.Ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
  97. return
  98. }
  99. //接口权限校验
  100. roleId := admin.RoleId
  101. list, e := system.GetMenuButtonApisByRoleId(roleId)
  102. if e != nil {
  103. utils.FileLog.Error("接口权限查询出错", e)
  104. cc.Ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
  105. return
  106. }
  107. var api string
  108. for _, v := range list {
  109. if v.Api != "" {
  110. api += v.Api + "&"
  111. }
  112. }
  113. api += "&" + models.BusinessConfMap["PublicApi"]
  114. //处理uri请求,去除前缀和参数
  115. api = strings.TrimRight(api, "&")
  116. uri = strings.Replace(uri, "/adminapi", "", 1)
  117. uris := strings.Split(uri, "?")
  118. uri = uris[0]
  119. //fmt.Println("uri:", uri)
  120. apis := strings.Split(api, "&")
  121. apiMap := make(map[string]bool, 0)
  122. for _, s := range apis {
  123. apiMap[s] = true
  124. }
  125. if !apiMap[uri] {
  126. utils.FileLog.Error("用户无权访问")
  127. cc.Ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
  128. return
  129. }
  130. cc.SysUser = admin
  131. } else {
  132. utils.FileLog.Error("请求方法类型错误")
  133. cc.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
  134. return
  135. }
  136. }
  137. // ChatConnect @Title 知识库问答创建对话连接
  138. // @Description 知识库问答创建对话连接
  139. // @Success 101 {object} response.ListResp
  140. // @router /chat/connect [get]
  141. func (cc *ChatWsController) ChatConnect() {
  142. if !ws.Allow(cc.SysUser.AdminId, ws.CONNECT_LIMITER) {
  143. utils.FileLog.Error("WebSocket连接太频繁,主动拒绝链接")
  144. cc.Ctx.ResponseWriter.WriteHeader(http.StatusTooManyRequests)
  145. return
  146. }
  147. wsCon, err := webSocketHandler(cc.Ctx.ResponseWriter, cc.Ctx.Request)
  148. if err != nil {
  149. utils.FileLog.Error("WebSocket连接失败:", err)
  150. cc.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
  151. return
  152. }
  153. facade.AddSession(cc.SysUser.AdminId, wsCon)
  154. }
  155. // upGrader 用于将HTTP连接升级为WebSocket连接
  156. var upGrader = websocket.Upgrader{
  157. ReadBufferSize: 1024,
  158. WriteBufferSize: 1024,
  159. CheckOrigin: func(r *http.Request) bool {
  160. return true
  161. },
  162. }
  163. // WebSocketHandler 处理WebSocket连接
  164. func webSocketHandler(w http.ResponseWriter, r *http.Request) (conn *websocket.Conn, err error) {
  165. conn, err = upGrader.Upgrade(w, r, nil)
  166. if err != nil {
  167. utils.FileLog.Error("升级协议失败:WebSocket:%s", err.Error())
  168. return
  169. }
  170. // 获取底层 TCP 连接并设置保活
  171. if tcpConn, ok := conn.NetConn().(*net.TCPConn); ok {
  172. _ = tcpConn.SetKeepAlive(true)
  173. _ = tcpConn.SetKeepAlivePeriod(ws.TcpTimeout)
  174. utils.FileLog.Info("TCP KeepAlive 已启用")
  175. }
  176. _ = conn.SetReadDeadline(time.Now().Add(ws.ReadTimeout))
  177. return
  178. }