globallimit.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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/cast"
  9. "github.com/spf13/viper"
  10. "golang.org/x/sync/errgroup"
  11. "strconv"
  12. "time"
  13. )
  14. type GlobalLimitService interface {
  15. GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error)
  16. AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
  17. EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
  18. DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
  19. EditGlobalLimitBySnail(ctx context.Context, req v1.GlobalLimitEditRequest) error
  20. }
  21. func NewGlobalLimitService(
  22. service *Service,
  23. globalLimitRepository repository.GlobalLimitRepository,
  24. duedate DuedateService,
  25. crawler CrawlerService,
  26. conf *viper.Viper,
  27. required RequiredService,
  28. parser ParserService,
  29. host HostService,
  30. tcpLimit TcpLimitService,
  31. udpLimit UdpLimitService,
  32. webLimit WebLimitService,
  33. gateWayGroup GatewayGroupService,
  34. hostRep repository.HostRepository,
  35. gateWayGroupRep repository.GatewayGroupRepository,
  36. ) GlobalLimitService {
  37. return &globalLimitService{
  38. Service: service,
  39. globalLimitRepository: globalLimitRepository,
  40. duedate: duedate,
  41. crawler: crawler,
  42. Url: conf.GetString("crawler.Url"),
  43. required: required,
  44. parser: parser,
  45. host: host,
  46. tcpLimit: tcpLimit,
  47. udpLimit: udpLimit,
  48. webLimit: webLimit,
  49. gateWayGroup: gateWayGroup,
  50. hostRep: hostRep,
  51. gateWayGroupRep: gateWayGroupRep,
  52. }
  53. }
  54. type globalLimitService struct {
  55. *Service
  56. globalLimitRepository repository.GlobalLimitRepository
  57. duedate DuedateService
  58. crawler CrawlerService
  59. Url string
  60. required RequiredService
  61. parser ParserService
  62. host HostService
  63. tcpLimit TcpLimitService
  64. udpLimit UdpLimitService
  65. webLimit WebLimitService
  66. gateWayGroup GatewayGroupService
  67. hostRep repository.HostRepository
  68. gateWayGroupRep repository.GatewayGroupRepository
  69. }
  70. func (s *globalLimitService) GlobalLimitRequire(ctx context.Context, req v1.GlobalLimitRequest) (res v1.GlobalLimitRequireResponse, err error) {
  71. res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId)
  72. if err != nil {
  73. return v1.GlobalLimitRequireResponse{}, err
  74. }
  75. configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId)
  76. if err != nil {
  77. return v1.GlobalLimitRequireResponse{}, fmt.Errorf("获取配置限制失败: %w", err)
  78. }
  79. bpsInt, err := strconv.Atoi(configCount.Bps)
  80. if err != nil {
  81. return v1.GlobalLimitRequireResponse{}, err
  82. }
  83. res.Bps = strconv.Itoa(bpsInt / 2 / 8)
  84. res.MaxBytesMonth = configCount.MaxBytesMonth
  85. res.Operator = configCount.Operator
  86. res.IpCount = configCount.IpCount
  87. domain, err := s.hostRep.GetDomainById(ctx, req.HostId)
  88. if err != nil {
  89. return v1.GlobalLimitRequireResponse{}, err
  90. }
  91. res.GlobalLimitName = strconv.Itoa(req.Uid) + "_" + strconv.Itoa(req.HostId) + "_" + domain
  92. return res, nil
  93. }
  94. func (s *globalLimitService) GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) {
  95. return s.globalLimitRepository.GetGlobalLimit(ctx, id)
  96. }
  97. func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  98. isExist, err := s.globalLimitRepository.IsGlobalLimitExistByHostId(ctx, int64(req.HostId))
  99. if err != nil {
  100. return err
  101. }
  102. if isExist {
  103. return fmt.Errorf("配置限制已存在")
  104. }
  105. require, err := s.GlobalLimitRequire(ctx, req)
  106. if err != nil {
  107. return err
  108. }
  109. gatewayGroupId, err := s.gateWayGroupRep.GetGatewayGroupWhereHostIdNull(ctx, require.Operator, require.IpCount)
  110. if err != nil {
  111. return err
  112. }
  113. formData := map[string]interface{}{
  114. "tag": require.GlobalLimitName,
  115. "bps": require.Bps,
  116. "max_bytes_month": require.MaxBytesMonth,
  117. "expired_at": require.ExpiredAt,
  118. }
  119. respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/new", "admin/new/waf_common_limit", formData)
  120. if err != nil {
  121. return err
  122. }
  123. ruleIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, require.GlobalLimitName)
  124. if err != nil {
  125. return err
  126. }
  127. if ruleIdBase == "" {
  128. res, err := s.parser.ParseAlert(string(respBody))
  129. if err != nil {
  130. return err
  131. }
  132. return fmt.Errorf(res)
  133. }
  134. ruleId, err := cast.ToIntE(ruleIdBase)
  135. if err != nil {
  136. return err
  137. }
  138. var tcpLimitRuleId, udpLimitRuleId, webLimitRuleId int
  139. g, gCtx := errgroup.WithContext(ctx)
  140. // 启动tcpLimit调用 - 使用独立的请求参数副本
  141. g.Go(func() error {
  142. tcpLimitReq := &v1.GeneralLimitRequireRequest{
  143. Tag: require.GlobalLimitName,
  144. HostId: req.HostId,
  145. RuleId: ruleId,
  146. Uid: req.Uid,
  147. }
  148. result, e := s.tcpLimit.AddTcpLimit(gCtx, tcpLimitReq)
  149. if e != nil {
  150. return fmt.Errorf("tcpLimit调用失败: %w", e)
  151. }
  152. if result != 0 {
  153. tcpLimitRuleId = result
  154. return nil
  155. }
  156. return fmt.Errorf("tcpLimit调用失败,Id为 %d", result)
  157. })
  158. // 启动udpLimit调用 - 使用独立的请求参数副本
  159. g.Go(func() error {
  160. udpLimitReq := &v1.GeneralLimitRequireRequest{
  161. Tag: require.GlobalLimitName,
  162. HostId: req.HostId,
  163. RuleId: ruleId,
  164. Uid: req.Uid,
  165. }
  166. result, e := s.udpLimit.AddUdpLimit(gCtx, udpLimitReq)
  167. if e != nil {
  168. return fmt.Errorf("udpLimit调用失败: %w", e)
  169. }
  170. if result != 0 {
  171. udpLimitRuleId = result
  172. return nil
  173. }
  174. return fmt.Errorf("udpLimit调用失败,Id为 %d", result)
  175. })
  176. // 启动webLimit调用 - 使用独立的请求参数副本
  177. g.Go(func() error {
  178. webLimitReq := &v1.GeneralLimitRequireRequest{
  179. Tag: require.GlobalLimitName,
  180. HostId: req.HostId,
  181. RuleId: ruleId,
  182. Uid: req.Uid,
  183. }
  184. result, e := s.webLimit.AddWebLimit(gCtx, webLimitReq)
  185. if e != nil {
  186. return fmt.Errorf("webLimit调用失败: %w", e)
  187. }
  188. if result != 0 {
  189. webLimitRuleId = result
  190. return nil
  191. }
  192. return fmt.Errorf("webLimit调用失败,Id为 %d", result)
  193. })
  194. if err := g.Wait(); err != nil {
  195. return err
  196. }
  197. t, err := time.Parse("2006-01-02 15:04:05", require.ExpiredAt)
  198. if err != nil {
  199. return err
  200. }
  201. expiredAt := t.Unix()
  202. err = s.globalLimitRepository.AddGlobalLimit(ctx, &model.GlobalLimit{
  203. HostId: req.HostId,
  204. RuleId: cast.ToInt(ruleId),
  205. Uid: req.Uid,
  206. GlobalLimitName: require.GlobalLimitName,
  207. Comment: req.Comment,
  208. TcpLimitRuleId: tcpLimitRuleId,
  209. UdpLimitRuleId: udpLimitRuleId,
  210. WebLimitRuleId: webLimitRuleId,
  211. GatewayGroupId: gatewayGroupId,
  212. ExpiredAt: expiredAt,
  213. })
  214. if err != nil {
  215. return err
  216. }
  217. err = s.gateWayGroupRep.EditGatewayGroup(ctx, &model.GatewayGroup{
  218. RuleId: gatewayGroupId,
  219. HostId: req.HostId,
  220. })
  221. return nil
  222. }
  223. func (s *globalLimitService) EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  224. require, err := s.GlobalLimitRequire(ctx, req)
  225. if err != nil {
  226. return err
  227. }
  228. formData := map[string]interface{}{
  229. "tag": require.GlobalLimitName,
  230. "bps": require.Bps,
  231. "max_bytes_month": require.MaxBytesMonth,
  232. "expired_at": require.ExpiredAt,
  233. }
  234. data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId))
  235. if err != nil {
  236. return err
  237. }
  238. respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(data.RuleId), "admin/edit/waf_common_limit", formData)
  239. if err != nil {
  240. return err
  241. }
  242. res, err := s.parser.ParseAlert(string(respBody))
  243. if err != nil {
  244. return err
  245. }
  246. if res != "" {
  247. return fmt.Errorf(res)
  248. }
  249. t, err := time.Parse("2006-01-02 15:04:05", require.ExpiredAt)
  250. if err != nil {
  251. return err
  252. }
  253. expiredAt := t.Unix()
  254. if err := s.globalLimitRepository.UpdateGlobalLimitByHostId(ctx, &model.GlobalLimit{
  255. HostId: req.HostId,
  256. Comment: req.Comment,
  257. ExpiredAt: expiredAt,
  258. }); err != nil {
  259. return err
  260. }
  261. return nil
  262. }
  263. func (s *globalLimitService) EditGlobalLimitBySnail(ctx context.Context, req v1.GlobalLimitEditRequest) error {
  264. configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId)
  265. if err != nil {
  266. return fmt.Errorf("获取配置限制失败: %w", err)
  267. }
  268. data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId))
  269. if err != nil {
  270. return err
  271. }
  272. t := time.Unix(req.ExpiredAt, 0)
  273. expiredAt := t.Format("2006-01-02 15:04:05")
  274. formData := map[string]interface{}{
  275. "tag": data.GlobalLimitName,
  276. "bps": configCount.Bps,
  277. "max_bytes_month": configCount.MaxBytesMonth,
  278. "expired_at": expiredAt,
  279. }
  280. respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(req.RuleId), "admin/edit/waf_common_limit", formData)
  281. if err != nil {
  282. return err
  283. }
  284. if respBody == nil {
  285. return nil
  286. }
  287. return nil
  288. }
  289. func (s *globalLimitService) DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  290. if err := s.globalLimitRepository.DeleteGlobalLimitByHostId(ctx, int64(req.HostId)); err != nil {
  291. return err
  292. }
  293. return nil
  294. }