gameshieldbackend.go 9.5 KB

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