gameshieldbackend.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
  6. "github.com/go-nunu/nunu-layout-advanced/internal/model"
  7. "github.com/go-nunu/nunu-layout-advanced/internal/repository"
  8. "github.com/spf13/viper"
  9. "strconv"
  10. "strings"
  11. )
  12. type GameShieldBackendService interface {
  13. GetGameShieldBackend(ctx context.Context, id int64) (*model.GameShieldBackend, error)
  14. GameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, int, error)
  15. AddGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
  16. EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
  17. DeleteGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
  18. GetGameShieldRequired(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (*v1.GetGameShieldRequiredResponse, int, error)
  19. }
  20. func NewGameShieldBackendService(
  21. service *Service,
  22. gameShieldBackendRepository repository.GameShieldBackendRepository,
  23. gameShieldRepository repository.GameShieldRepository,
  24. crawlerService CrawlerService,
  25. gameShieldPublicIpService GameShieldPublicIpService,
  26. duedate DuedateService,
  27. formatter FormatterService,
  28. parser ParserService,
  29. required RequiredService,
  30. conf *viper.Viper,
  31. shieldService GameShieldService,
  32. ) GameShieldBackendService {
  33. return &gameShieldBackendService{
  34. Service: service,
  35. gameShieldBackendRepository: gameShieldBackendRepository,
  36. gameShieldRepository: gameShieldRepository,
  37. crawlerService: crawlerService,
  38. gameShieldPublicIpService: gameShieldPublicIpService,
  39. duedate: duedate,
  40. formatter: formatter,
  41. parser: parser,
  42. required: required,
  43. Url: conf.GetString("crawler.Url"),
  44. shieldService: shieldService,
  45. }
  46. }
  47. type gameShieldBackendService struct {
  48. *Service
  49. gameShieldBackendRepository repository.GameShieldBackendRepository
  50. crawlerService CrawlerService
  51. gameShieldRepository repository.GameShieldRepository
  52. gameShieldPublicIpService GameShieldPublicIpService
  53. duedate DuedateService
  54. formatter FormatterService
  55. Url string
  56. parser ParserService
  57. required RequiredService
  58. shieldService GameShieldService
  59. }
  60. func (s *gameShieldBackendService) GetGameShieldRequired(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (*v1.GetGameShieldRequiredResponse, int, error) {
  61. var res v1.GetGameShieldRequiredResponse
  62. var err error
  63. var count int
  64. if req.Uid == 0 {
  65. return nil, 0, fmt.Errorf("uid is required")
  66. }
  67. res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId)
  68. if err != nil {
  69. return nil, 0, err
  70. }
  71. gameShield, err := s.gameShieldRepository.GetGameShieldByHostId(ctx, req.HostId)
  72. if err != nil {
  73. return nil, 0, err
  74. }
  75. res.RuleId = gameShield.RuleId
  76. oldBackend, err := s.gameShieldBackendRepository.GetGameShieldBackendByHostId(ctx, req.HostId)
  77. if err != nil {
  78. return nil, 0, err
  79. }
  80. if len(oldBackend) != 0 {
  81. count = oldBackend[0].KeySort
  82. }
  83. OldBackend, err := s.formatter.OldFormat(ctx, &oldBackend)
  84. res.Backend, err = s.formatter.FormatBackendData(ctx, req, OldBackend, count)
  85. if err != nil {
  86. return nil, 0, err
  87. }
  88. res.Cookie, err = s.crawlerService.GetLoginCookie(ctx)
  89. if err != nil {
  90. return nil, 0, err
  91. }
  92. res.DunName = gameShield.DunName
  93. return &res, count, nil
  94. }
  95. func (s *gameShieldBackendService) GetGameShieldBackend(ctx context.Context, id int64) (*model.GameShieldBackend, error) {
  96. res, err := s.gameShieldBackendRepository.GetGameShieldBackendById(ctx, id)
  97. if err != nil {
  98. return nil, err
  99. }
  100. return res, nil
  101. }
  102. func (s *gameShieldBackendService) GameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, int, error) {
  103. require, count, err := s.GetGameShieldRequired(ctx, req)
  104. if err != nil {
  105. return "", 0, err
  106. }
  107. tokenUrl := s.Url + "admin/info/rule/edit?&__goadmin_edit_pk=" + strconv.Itoa(require.RuleId) + "_" + require.DunName
  108. tokens, err := s.crawlerService.GetFormTokens(ctx, tokenUrl, require.Cookie)
  109. if err != nil {
  110. return "", 0, err
  111. }
  112. formData := map[string]interface{}{
  113. "app_name": require.DunName,
  114. "gateway_group_id": 4,
  115. "backend": require.Backend,
  116. "rule_id": require.RuleId,
  117. "expired_at": require.ExpiredAt,
  118. "max_device_count": 0,
  119. "sdk_args": "",
  120. "__go_admin_previous_": tokens["previous"],
  121. "__go_admin_t_": tokens["t"],
  122. }
  123. sendUrl := s.Url + "admin/edit/rule"
  124. respBody, err := s.crawlerService.SendFormData(ctx, sendUrl, require.Cookie, formData)
  125. if err != nil {
  126. return "", 0, err
  127. }
  128. // 解析响应内容中的 alert 消息
  129. res, err := s.parser.ParseAlert(string(respBody))
  130. if err != nil {
  131. return "", 0, err
  132. }
  133. if res != "" {
  134. return "", 0, fmt.Errorf(res)
  135. }
  136. KeyAndField, err := s.required.GetKeyAndField(ctx, require.DunName, "rule_id")
  137. if err != nil {
  138. return "", 0, err
  139. }
  140. timeBase, err := s.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(req.Uid), req.HostId)
  141. if err != nil {
  142. return "", 0, err
  143. }
  144. timestampSec, err := strconv.ParseInt(timeBase, 10, 64)
  145. if err != nil {
  146. return "", 0, err
  147. }
  148. if err := s.gameShieldRepository.UpdateGameShieldByHostId(ctx, &model.GameShield{HostId: req.HostId, Key: KeyAndField.Key, ExpireTime: timestampSec}); err != nil {
  149. return "", 0, err
  150. }
  151. return res, count, nil
  152. }
  153. func (s *gameShieldBackendService) AddGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
  154. res, count, err := s.GameShieldBackend(ctx, req)
  155. if err != nil {
  156. return "", err
  157. }
  158. saveData, err := s.formatter.TidyFormatBackendData(ctx, req, count)
  159. if err != nil {
  160. return "", err
  161. }
  162. if err := s.SaveGameShieldBackend(ctx, saveData, req.HostId); err != nil {
  163. return "", err
  164. }
  165. return res, nil
  166. }
  167. func (s *gameShieldBackendService) EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
  168. // 1. 获取当前所有数据库记录
  169. currentData, err := s.gameShieldBackendRepository.GetGameShieldBackendByHostId(ctx, req.HostId)
  170. if err != nil {
  171. return "", fmt.Errorf("获取当前配置失败: %w", err)
  172. }
  173. // 2. 创建当前记录的副本用于模拟修改
  174. simulatedData := make([]model.GameShieldBackend, len(currentData))
  175. copy(simulatedData, currentData)
  176. // 3. 创建ID到索引的映射,方便查找和修改
  177. idToIndex := make(map[int64]int)
  178. for i, item := range simulatedData {
  179. idToIndex[int64(item.Id)] = i
  180. }
  181. // 4. 在副本上应用修改
  182. for _, v := range req.Items {
  183. if v.Id == 0 {
  184. return "", fmt.Errorf("id 不能为空")
  185. }
  186. // 查找对应记录
  187. idx, exists := idToIndex[int64(v.Id)]
  188. if !exists {
  189. return "", fmt.Errorf("ID为%d的记录不存在", v.Id)
  190. }
  191. // 更新记录(只更新需要修改的字段)
  192. simulatedData[idx].SourceMachineIP = v.SourceMachineIP
  193. simulatedData[idx].ConnectPort = v.ConnectPort
  194. simulatedData[idx].Protocol = v.Protocol
  195. simulatedData[idx].SdkPort = v.SdkPort
  196. simulatedData[idx].SdkIp = v.SdkIp
  197. simulatedData[idx].Type = v.Type
  198. simulatedData[idx].MaxBandwidth = v.MaxBandwidth
  199. }
  200. // 5. 使用模拟修改后的数据进行验证
  201. // 转换数据格式
  202. simulatedBackend, err := s.formatter.OldFormat(ctx, &simulatedData)
  203. if err != nil {
  204. return "", fmt.Errorf("格式化模拟数据失败: %w", err)
  205. }
  206. // 验证修改后的配置
  207. err = s.formatter.ValidateBackendData(ctx, simulatedBackend, req.HostId)
  208. if err != nil {
  209. return "", fmt.Errorf("验证失败: %w", err)
  210. }
  211. // 6. 验证通过,执行实际的数据库修改
  212. for _, v := range req.Items {
  213. if err := s.gameShieldBackendRepository.EditGameShieldBackend(ctx, &v); err != nil {
  214. return "", fmt.Errorf("修改数据失败(ID:%d): %w", v.Id, err)
  215. }
  216. }
  217. // 7. 更新远程配置
  218. res, _, err := s.GameShieldBackend(ctx, &v1.GameShieldBackendArrayRequest{
  219. HostId: req.HostId,
  220. Uid: req.Uid,
  221. Items: nil,
  222. })
  223. if err != nil {
  224. return "", fmt.Errorf("更新配置失败: %w", err)
  225. }
  226. return res, nil
  227. }
  228. func (s *gameShieldBackendService) DeleteGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
  229. for _, v := range req.Items {
  230. if err := s.gameShieldBackendRepository.DeleteGameShieldBackend(ctx, int64(v.Id)); err != nil {
  231. return "", err
  232. }
  233. }
  234. res, _, err := s.GameShieldBackend(ctx, &v1.GameShieldBackendArrayRequest{HostId: req.HostId, Uid: req.Uid, Items: nil})
  235. if err != nil {
  236. return "", err
  237. }
  238. return res, nil
  239. }
  240. func (s *gameShieldBackendService) SaveGameShieldBackend(ctx context.Context, req map[string]v1.SendGameShieldBackend, hostId int) error {
  241. for k, v := range req {
  242. parts := strings.Split(v.Addr[0], ":")
  243. keyName := strings.Split(k, "key")[1]
  244. key, err := strconv.Atoi(keyName)
  245. if err != nil {
  246. return err
  247. }
  248. if v.Type != "pc" {
  249. v.SdkIp = "127.0.0.1"
  250. }
  251. if err := s.gameShieldBackendRepository.AddGameShieldBackend(ctx,
  252. &model.GameShieldBackend{
  253. HostId: hostId,
  254. KeySort: key,
  255. SourceMachineIP: parts[0],
  256. Protocol: v.Protocol,
  257. ProxyAddr: v.ProxyAddr,
  258. ConnectPort: parts[1],
  259. SdkIp: v.SdkIp,
  260. SdkPort: strconv.Itoa(v.SdkPort),
  261. Type: v.Type,
  262. // 可以添加其他字段
  263. }); err != nil {
  264. return err
  265. }
  266. }
  267. return nil
  268. }