host.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. package service
  2. import (
  3. "context"
  4. v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
  5. "github.com/go-nunu/nunu-layout-advanced/internal/model"
  6. "github.com/go-nunu/nunu-layout-advanced/internal/repository"
  7. "github.com/spf13/cast"
  8. "strconv"
  9. "strings"
  10. "time"
  11. )
  12. // HostService 接口定义
  13. type HostService interface {
  14. GetHost(ctx context.Context, id int64) (*model.Host, error)
  15. GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error)
  16. GetGlobalLimitConfig(ctx context.Context, hostId int) (v1.GlobalLimitConfigResponse, error)
  17. GetTcpLimitConfig(ctx context.Context, hostId int) (v1.TcpLimitRequest, error)
  18. GetUdpLimitConfig(ctx context.Context, hostId int) (v1.UdpLimitRequest, error)
  19. GetWebLimitConfig(ctx context.Context, hostId int) (v1.WebLimitRequest, error)
  20. // 检查是否过期 到期false 未到期true
  21. CheckExpired(ctx context.Context, uid int64, hostId int64) (bool, error)
  22. }
  23. func NewHostService(
  24. service *Service,
  25. hostRepository repository.HostRepository,
  26. ) HostService {
  27. return &hostService{
  28. Service: service,
  29. hostRepository: hostRepository,
  30. }
  31. }
  32. // 常量定义,包含新增的配置项名称
  33. const (
  34. ConfigOnlineDevices = "在线设备数"
  35. ConfigRuleEntries = "规则条目"
  36. ConfigMaxBandwidth = "高带宽转发规则条目"
  37. ConfigSourceMachines = "支持源机"
  38. ConfigBps = "带宽"
  39. ConfigMaxProtection = "高防防护能力"
  40. ConfigPortCount = "防御端口数量"
  41. ConfigDomainCount = "防御域名(需要备案)"
  42. ConfigOperator = "高防线路"
  43. ConfigIpCount = "高防节点IP"
  44. NodeArea = "节点区域"
  45. IsBanUdp = "UDP协议"
  46. IsBanOverseas = "禁用海外"
  47. )
  48. // unitSuffixMap 存储需要去除的单位后缀
  49. var unitSuffixMap = map[string]string{
  50. ConfigOnlineDevices: "个",
  51. ConfigRuleEntries: "个",
  52. ConfigMaxBandwidth: "条",
  53. ConfigIpCount: "个",
  54. }
  55. type hostService struct {
  56. *Service
  57. hostRepository repository.HostRepository
  58. }
  59. func (s *hostService) GetHost(ctx context.Context, id int64) (*model.Host, error) {
  60. return s.hostRepository.GetHost(ctx, id)
  61. }
  62. // GetHostConfig 保持不变,它是一个通用的底层数据获取方法。
  63. func (s *hostService) GetHostConfig(ctx context.Context, hostId int) ([]map[string]string, error) {
  64. configOptions, err := s.hostRepository.GetHostConfig(ctx, hostId)
  65. if err != nil {
  66. return nil, err
  67. }
  68. // 2. 收集ID和建立映射关系 (优化部分)
  69. var configIDs []int
  70. // 只收集那些我们需要查询详情的 option ID
  71. var optionIDsToFetch []int
  72. optionMap := make(map[int]int)
  73. qtyMap := make(map[int]int)
  74. for _, item := range configOptions {
  75. configIDs = append(configIDs, item.Configid)
  76. qtyMap[item.Configid] = item.Qty
  77. // 核心优化:只有当数量为0时,我们才需要Option的名称,
  78. // 因此才需要记录其ID用于后续查询,并建立 configID -> optionID 的映射。
  79. if item.Qty == 0 {
  80. optionIDsToFetch = append(optionIDsToFetch, item.Optionid)
  81. optionMap[item.Configid] = item.Optionid
  82. }
  83. }
  84. // 3. 获取配置和选项数据
  85. var configs []v1.ProductConfigOption
  86. if len(configIDs) > 0 {
  87. configs, err = s.hostRepository.GetProductConfigOption(ctx, configIDs)
  88. if err != nil {
  89. return nil, err
  90. }
  91. }
  92. // 只有在确实需要查询的情况下才执行
  93. var options []v1.ProductConfigOptionSub
  94. if len(optionIDsToFetch) > 0 {
  95. options, err = s.hostRepository.GetProductConfigOptionSub(ctx, optionIDsToFetch)
  96. if err != nil {
  97. return nil, err
  98. }
  99. }
  100. // 4. 转换选项为关联数组
  101. optionsByID := make(map[int]v1.ProductConfigOptionSub)
  102. for _, option := range options {
  103. optionsByID[option.ID] = option
  104. }
  105. // 5. 构建结果数据 (逻辑更清晰)
  106. var data []map[string]string
  107. for _, config := range configs {
  108. var optionName string
  109. // 直接通过qtyMap判断,逻辑更直接
  110. if qty := qtyMap[config.ID]; qty != 0 {
  111. // 如果数量不为0,直接使用数量作为名称
  112. optionName = strconv.Itoa(qty)
  113. } else {
  114. // 否则,我们知道它一定在 optionMap 和 optionsByID 中 (如果数据一致)
  115. optionID := optionMap[config.ID] // 这个查找现在是必要的
  116. if opt, ok := optionsByID[optionID]; ok {
  117. optionName = opt.OptionName
  118. }
  119. }
  120. data = append(data, map[string]string{
  121. "config_name": config.OptionName,
  122. "option_name": optionName,
  123. })
  124. }
  125. return data, nil
  126. }
  127. // cleanConfigOptionName 简化后的清理函数,直接返回清理后的字符串。
  128. func (s *hostService) cleanConfigOptionName(configName string, optionName string) string {
  129. // 根据配置名称去除相应的单位后缀
  130. if suffix, ok := unitSuffixMap[configName]; ok {
  131. optionName = strings.TrimSuffix(optionName, suffix)
  132. }
  133. return optionName
  134. }
  135. // getHostConfigsMap 新增的辅助函数,用于获取所有清理后的配置映射。
  136. func (s *hostService) getHostConfigsMap(ctx context.Context, hostId int) (map[string]string, error) {
  137. baseData, err := s.GetHostConfig(ctx, hostId)
  138. if err != nil {
  139. return nil, err
  140. }
  141. configsMap := make(map[string]string)
  142. for _, item := range baseData {
  143. configName := item["config_name"]
  144. optionName := item["option_name"]
  145. // 将清理后的值存储到 map 中
  146. configsMap[configName] = s.cleanConfigOptionName(configName, optionName)
  147. }
  148. return configsMap, nil
  149. }
  150. func (s *hostService) GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error) {
  151. // 调用新辅助函数获取处理好的配置映射
  152. configsMap, err := s.getHostConfigsMap(ctx, hostId)
  153. if err != nil {
  154. return v1.GameShieldHostBackendConfigResponse{}, err
  155. }
  156. var data v1.GameShieldHostBackendConfigResponse
  157. var parseErr error // 用于统一处理类型转换错误
  158. // 从映射中获取值并进行类型转换
  159. if val, ok := configsMap[ConfigOnlineDevices]; ok {
  160. data.OnlineDevicesCount, parseErr = cast.ToInt64E(val)
  161. if parseErr != nil {
  162. return data, parseErr
  163. }
  164. }
  165. if val, ok := configsMap[ConfigRuleEntries]; ok {
  166. data.RuleEntriesCount, parseErr = cast.ToInt64E(val)
  167. if parseErr != nil {
  168. return data, parseErr
  169. }
  170. }
  171. if val, ok := configsMap[ConfigMaxBandwidth]; ok {
  172. data.MaxBandwidthCount, parseErr = cast.ToInt64E(val)
  173. if parseErr != nil {
  174. return data, parseErr
  175. }
  176. }
  177. if val, ok := configsMap[ConfigSourceMachines]; ok {
  178. data.SourceMachinesCount, parseErr = cast.ToInt64E(val)
  179. if parseErr != nil {
  180. return data, parseErr
  181. }
  182. }
  183. return data, nil
  184. }
  185. func (s *hostService) GetGlobalLimitConfig(ctx context.Context, hostId int) (v1.GlobalLimitConfigResponse, error) {
  186. configsMap, err := s.getHostConfigsMap(ctx, hostId)
  187. if err != nil {
  188. return v1.GlobalLimitConfigResponse{}, err
  189. }
  190. data := v1.GlobalLimitConfigResponse{
  191. MaxBytesMonth: "0",
  192. Bps: "0",
  193. IpCount: 0,
  194. Operator: 0,
  195. NodeArea: "",
  196. ConfigMaxProtection: "",
  197. IsBanUdp: 0,
  198. }
  199. if val, ok := configsMap[ConfigBps]; ok {
  200. data.Bps = val
  201. }
  202. //if val, ok := configsMap[ConfigMaxBytesMonth]; ok {
  203. // data.MaxBytesMonth = val
  204. //}
  205. if val, ok := configsMap[ConfigPortCount]; ok {
  206. data.PortCount, err = cast.ToIntE(val)
  207. if err != nil {
  208. return data, err
  209. }
  210. }
  211. if val, ok := configsMap[ConfigDomainCount]; ok {
  212. data.DomainCount, err = cast.ToIntE(val)
  213. if err != nil {
  214. return data, err
  215. }
  216. }
  217. if val, ok := configsMap[ConfigOperator]; ok {
  218. if val == "电信" {
  219. data.IpCount = 1
  220. }
  221. if val == "BGP" {
  222. data.IpCount = 2
  223. }
  224. }
  225. if val, ok := configsMap[ConfigIpCount]; ok {
  226. data.Operator, err = cast.ToIntE(val)
  227. if err != nil {
  228. return data, err
  229. }
  230. }
  231. if val, ok := configsMap[NodeArea]; ok {
  232. data.NodeArea = val
  233. }
  234. if val, ok := configsMap[ConfigMaxProtection]; ok {
  235. data.ConfigMaxProtection = val
  236. }
  237. if val, ok := configsMap[IsBanUdp]; ok {
  238. if val == "开通" {
  239. data.IsBanUdp = 1
  240. }
  241. if val == "关闭" {
  242. data.IsBanUdp = 0
  243. }
  244. }
  245. return data, nil
  246. }
  247. // GetTcpLimitConfig 修正返回类型,并使用新的辅助函数
  248. func (s *hostService) GetTcpLimitConfig(ctx context.Context, hostId int) (v1.TcpLimitRequest, error) {
  249. _, err := s.getHostConfigsMap(ctx, hostId)
  250. if err != nil {
  251. return v1.TcpLimitRequest{}, err
  252. }
  253. data := v1.TcpLimitRequest{
  254. ConnCount: 0,
  255. ConnDuration: "0s",
  256. MaxConnCount: 0,
  257. }
  258. return data, nil // 返回结构体
  259. }
  260. // GetUdpLimitConfig
  261. func (s *hostService) GetUdpLimitConfig(ctx context.Context, hostId int) (v1.UdpLimitRequest, error) {
  262. _, err := s.getHostConfigsMap(ctx, hostId)
  263. if err != nil {
  264. return v1.UdpLimitRequest{}, err
  265. }
  266. data := v1.UdpLimitRequest{
  267. QosPacketCount: 0,
  268. QosPacketDuration: "0s",
  269. MaxConnCount: 0,
  270. }
  271. return data, nil
  272. }
  273. // GetWebLimitConfig 修正返回类型,并使用新的辅助函数
  274. func (s *hostService) GetWebLimitConfig(ctx context.Context, hostId int) (v1.WebLimitRequest, error) {
  275. _, err := s.getHostConfigsMap(ctx, hostId)
  276. if err != nil {
  277. return v1.WebLimitRequest{}, err
  278. }
  279. data := v1.WebLimitRequest{
  280. QpsCount: 0,
  281. QpsDuration: "0s",
  282. }
  283. return data, nil
  284. }
  285. // 检查是否过期 到期false 未到期true
  286. func (s *hostService) CheckExpired(ctx context.Context, uid int64, hostId int64) (bool, error) {
  287. var expireTime string
  288. expireTime, err := s.hostRepository.GetExpireTime(ctx, uid, hostId)
  289. if err != nil {
  290. return false, err
  291. }
  292. if expireTime == "" {
  293. return true, nil
  294. }
  295. unixTime, err := strconv.ParseInt(expireTime, 10, 64)
  296. if err != nil {
  297. return false, err
  298. }
  299. now := time.Now().Unix() // 当前时间戳(秒级)
  300. if now > unixTime {
  301. return false, nil
  302. }
  303. return true, nil
  304. }