globallimit.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. res.Bps = configCount.Bps
  80. res.MaxBytesMonth = configCount.MaxBytesMonth
  81. res.Operator = configCount.Operator
  82. res.IpCount = configCount.IpCount
  83. domain, err := s.hostRep.GetDomainById(ctx, req.HostId)
  84. if err != nil {
  85. return v1.GlobalLimitRequireResponse{}, err
  86. }
  87. res.GlobalLimitName = strconv.Itoa(req.Uid) + "_" + strconv.Itoa(req.HostId) + "_" + domain
  88. return res, nil
  89. }
  90. func (s *globalLimitService) GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) {
  91. return s.globalLimitRepository.GetGlobalLimit(ctx, id)
  92. }
  93. func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  94. isExist, err := s.globalLimitRepository.IsGlobalLimitExistByHostId(ctx, int64(req.HostId))
  95. if err != nil {
  96. return err
  97. }
  98. if isExist {
  99. return fmt.Errorf("配置限制已存在")
  100. }
  101. require, err := s.GlobalLimitRequire(ctx, req)
  102. if err != nil {
  103. return err
  104. }
  105. gatewayGroupId, err := s.gateWayGroupRep.GetGatewayGroupWhereHostIdNull(ctx, require.Operator, require.IpCount)
  106. if err != nil {
  107. return err
  108. }
  109. formData := map[string]interface{}{
  110. "tag": require.GlobalLimitName,
  111. "bps": require.Bps,
  112. "max_bytes_month": require.MaxBytesMonth,
  113. "expired_at": require.ExpiredAt,
  114. }
  115. respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/new", "admin/new/waf_common_limit", formData)
  116. if err != nil {
  117. return err
  118. }
  119. ruleIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, require.GlobalLimitName)
  120. if err != nil {
  121. return err
  122. }
  123. if ruleIdBase == "" {
  124. res, err := s.parser.ParseAlert(string(respBody))
  125. if err != nil {
  126. return err
  127. }
  128. return fmt.Errorf(res)
  129. }
  130. ruleId, err := cast.ToIntE(ruleIdBase)
  131. if err != nil {
  132. return err
  133. }
  134. var tcpLimitRuleId, udpLimitRuleId, webLimitRuleId int
  135. g, gCtx := errgroup.WithContext(ctx)
  136. // 启动tcpLimit调用 - 使用独立的请求参数副本
  137. g.Go(func() error {
  138. tcpLimitReq := &v1.GeneralLimitRequireRequest{
  139. Tag: require.GlobalLimitName,
  140. HostId: req.HostId,
  141. RuleId: ruleId,
  142. Uid: req.Uid,
  143. }
  144. result, e := s.tcpLimit.AddTcpLimit(gCtx, tcpLimitReq)
  145. if e != nil {
  146. return fmt.Errorf("tcpLimit调用失败: %w", e)
  147. }
  148. if result != 0 {
  149. tcpLimitRuleId = result
  150. return nil
  151. }
  152. return fmt.Errorf("tcpLimit调用失败,Id为 %d", result)
  153. })
  154. // 启动udpLimit调用 - 使用独立的请求参数副本
  155. g.Go(func() error {
  156. udpLimitReq := &v1.GeneralLimitRequireRequest{
  157. Tag: require.GlobalLimitName,
  158. HostId: req.HostId,
  159. RuleId: ruleId,
  160. Uid: req.Uid,
  161. }
  162. result, e := s.udpLimit.AddUdpLimit(gCtx, udpLimitReq)
  163. if e != nil {
  164. return fmt.Errorf("udpLimit调用失败: %w", e)
  165. }
  166. if result != 0 {
  167. udpLimitRuleId = result
  168. return nil
  169. }
  170. return fmt.Errorf("udpLimit调用失败,Id为 %d", result)
  171. })
  172. // 启动webLimit调用 - 使用独立的请求参数副本
  173. g.Go(func() error {
  174. webLimitReq := &v1.GeneralLimitRequireRequest{
  175. Tag: require.GlobalLimitName,
  176. HostId: req.HostId,
  177. RuleId: ruleId,
  178. Uid: req.Uid,
  179. }
  180. result, e := s.webLimit.AddWebLimit(gCtx, webLimitReq)
  181. if e != nil {
  182. return fmt.Errorf("webLimit调用失败: %w", e)
  183. }
  184. if result != 0 {
  185. webLimitRuleId = result
  186. return nil
  187. }
  188. return fmt.Errorf("webLimit调用失败,Id为 %d", result)
  189. })
  190. if err := g.Wait(); err != nil {
  191. return err
  192. }
  193. t, err := time.Parse("2006-01-02 15:04:05", require.ExpiredAt)
  194. if err != nil {
  195. return err
  196. }
  197. expiredAt := t.Unix()
  198. err = s.globalLimitRepository.AddGlobalLimit(ctx, &model.GlobalLimit{
  199. HostId: req.HostId,
  200. RuleId: cast.ToInt(ruleId),
  201. Uid: req.Uid,
  202. GlobalLimitName: require.GlobalLimitName,
  203. Comment: req.Comment,
  204. TcpLimitRuleId: tcpLimitRuleId,
  205. UdpLimitRuleId: udpLimitRuleId,
  206. WebLimitRuleId: webLimitRuleId,
  207. GatewayGroupId: gatewayGroupId,
  208. ExpiredAt: expiredAt,
  209. })
  210. if err != nil {
  211. return err
  212. }
  213. err = s.gateWayGroupRep.EditGatewayGroup(ctx, &model.GatewayGroup{
  214. RuleId: gatewayGroupId,
  215. HostId: req.HostId,
  216. })
  217. return nil
  218. }
  219. func (s *globalLimitService) EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  220. require, err := s.GlobalLimitRequire(ctx, req)
  221. if err != nil {
  222. return err
  223. }
  224. formData := map[string]interface{}{
  225. "tag": require.GlobalLimitName,
  226. "bps": require.Bps,
  227. "max_bytes_month": require.MaxBytesMonth,
  228. "expired_at": require.ExpiredAt,
  229. }
  230. data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId))
  231. if err != nil {
  232. return err
  233. }
  234. 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)
  235. if err != nil {
  236. return err
  237. }
  238. res, err := s.parser.ParseAlert(string(respBody))
  239. if err != nil {
  240. return err
  241. }
  242. if res != "" {
  243. return fmt.Errorf(res)
  244. }
  245. t, err := time.Parse("2006-01-02 15:04:05", require.ExpiredAt)
  246. if err != nil {
  247. return err
  248. }
  249. expiredAt := t.Unix()
  250. if err := s.globalLimitRepository.UpdateGlobalLimitByHostId(ctx, &model.GlobalLimit{
  251. HostId: req.HostId,
  252. Comment: req.Comment,
  253. ExpiredAt: expiredAt,
  254. }); err != nil {
  255. return err
  256. }
  257. return nil
  258. }
  259. func (s *globalLimitService) EditGlobalLimitBySnail(ctx context.Context, req v1.GlobalLimitEditRequest) error {
  260. configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId)
  261. if err != nil {
  262. return fmt.Errorf("获取配置限制失败: %w", err)
  263. }
  264. data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId))
  265. if err != nil {
  266. return err
  267. }
  268. t := time.Unix(req.ExpiredAt, 0)
  269. expiredAt := t.Format("2006-01-02 15:04:05")
  270. formData := map[string]interface{}{
  271. "tag": data.GlobalLimitName,
  272. "bps": configCount.Bps,
  273. "max_bytes_month": configCount.MaxBytesMonth,
  274. "expired_at": expiredAt,
  275. }
  276. 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)
  277. if err != nil {
  278. return err
  279. }
  280. if respBody == nil {
  281. return nil
  282. }
  283. return nil
  284. }
  285. func (s *globalLimitService) DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
  286. if err := s.globalLimitRepository.DeleteGlobalLimitByHostId(ctx, int64(req.HostId)); err != nil {
  287. return err
  288. }
  289. return nil
  290. }