diff --git a/internal/db/models/node_task_dao.go b/internal/db/models/node_task_dao.go index acab9fd5..df317dd1 100644 --- a/internal/db/models/node_task_dao.go +++ b/internal/db/models/node_task_dao.go @@ -34,6 +34,7 @@ const ( NodeTaskTypeWebPPolicyChanged NodeTaskType = "webPPolicyChanged" // WebP策略变化 NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务 NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化 + NodeTaskTypePlanChanged NodeTaskType = "planChanged" // 套餐变化 // NS相关 diff --git a/internal/db/models/plan_dao.go b/internal/db/models/plan_dao.go index e62b1e87..6edc6fa9 100644 --- a/internal/db/models/plan_dao.go +++ b/internal/db/models/plan_dao.go @@ -49,7 +49,12 @@ func (this *PlanDAO) EnablePlan(tx *dbs.Tx, id uint32) error { // DisablePlan 禁用条目 func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error { - _, err := this.Query(tx). + clusterId, err := this.FindPlanClusterId(tx, id) + if err != nil { + return err + } + + _, err = this.Query(tx). Pk(id). Set("state", PlanStateDisabled). Update() @@ -57,7 +62,7 @@ func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error { return err } - return this.NotifyUpdate(tx, id) + return this.NotifyUpdate(tx, id, clusterId) } // FindEnabledPlan 查找启用中的条目 @@ -175,18 +180,18 @@ func (this *PlanDAO) FindEnabledPlanTrafficLimit(tx *dbs.Tx, planId int64, cache return config, nil } -// NotifyUpdate 通知变更 -func (this *PlanDAO) NotifyUpdate(tx *dbs.Tx, planId int64) error { - // 这里不要加入状态参数,因为需要适应删除后的更新 - clusterId, err := this.Query(tx). +// FindPlanClusterId 查找套餐所属集群 +func (this *PlanDAO) FindPlanClusterId(tx *dbs.Tx, planId int64) (clusterId int64, err error) { + return this.Query(tx). Pk(planId). Result("clusterId"). FindInt64Col(0) - if err != nil { - return err - } - if clusterId > 0 { - return SharedNodeClusterDAO.NotifyUpdate(tx, clusterId) - } - return nil +} + +// NotifyUpdate 通知变更 +func (this *PlanDAO) NotifyUpdate(tx *dbs.Tx, planId int64, clusterId int64) error { + if clusterId <= 0 { + return nil + } + return SharedNodeClusterDAO.NotifyUpdate(tx, clusterId) } diff --git a/internal/db/models/plan_model.go b/internal/db/models/plan_model.go index f2a4811e..87b6c233 100644 --- a/internal/db/models/plan_model.go +++ b/internal/db/models/plan_model.go @@ -6,9 +6,10 @@ const ( PlanField_Id dbs.FieldName = "id" // ID PlanField_IsOn dbs.FieldName = "isOn" // 是否启用 PlanField_Name dbs.FieldName = "name" // 套餐名 - PlanField_Description dbs.FieldName = "description" // 描述 + PlanField_Description dbs.FieldName = "description" // 套餐简介 PlanField_ClusterId dbs.FieldName = "clusterId" // 集群ID PlanField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制 + PlanField_BandwidthLimitPerNode dbs.FieldName = "bandwidthLimitPerNode" // 带宽限制 PlanField_Features dbs.FieldName = "features" // 允许的功能 PlanField_HasFullFeatures dbs.FieldName = "hasFullFeatures" // 是否有完整的功能 PlanField_TrafficPrice dbs.FieldName = "trafficPrice" // 流量价格设定 @@ -33,9 +34,10 @@ type Plan struct { Id uint32 `field:"id"` // ID IsOn bool `field:"isOn"` // 是否启用 Name string `field:"name"` // 套餐名 - Description string `field:"description"` // 描述 + Description string `field:"description"` // 套餐简介 ClusterId uint32 `field:"clusterId"` // 集群ID TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制 + BandwidthLimitPerNode dbs.JSON `field:"bandwidthLimitPerNode"` // 带宽限制 Features dbs.JSON `field:"features"` // 允许的功能 HasFullFeatures bool `field:"hasFullFeatures"` // 是否有完整的功能 TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定 @@ -59,9 +61,10 @@ type PlanOperator struct { Id any // ID IsOn any // 是否启用 Name any // 套餐名 - Description any // 描述 + Description any // 套餐简介 ClusterId any // 集群ID TrafficLimit any // 流量限制 + BandwidthLimitPerNode any // 带宽限制 Features any // 允许的功能 HasFullFeatures any // 是否有完整的功能 TrafficPrice any // 流量价格设定 diff --git a/internal/db/models/server_dao.go b/internal/db/models/server_dao.go index bef1052f..519cca20 100644 --- a/internal/db/models/server_dao.go +++ b/internal/db/models/server_dao.go @@ -1322,28 +1322,10 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer } // 套餐是否依然有效 - plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), cacheMap) - if err != nil { - return nil, err - } - if plan != nil { - config.UserPlan = &serverconfigs.UserPlanConfig{ - Id: int64(userPlan.Id), - DayTo: userPlan.DayTo, - Plan: &serverconfigs.PlanConfig{ - Id: int64(plan.Id), - Name: plan.Name, - }, - } - - if len(plan.TrafficLimit) > 0 && (config.TrafficLimit == nil || !config.TrafficLimit.IsOn) { - var trafficLimitConfig = &serverconfigs.TrafficLimitConfig{} - err = json.Unmarshal(plan.TrafficLimit, trafficLimitConfig) - if err != nil { - return nil, err - } - config.TrafficLimit = trafficLimitConfig - } + config.UserPlan = &serverconfigs.UserPlanConfig{ + Id: int64(userPlan.Id), + DayTo: userPlan.DayTo, + PlanId: int64(userPlan.PlanId), } } } @@ -2358,8 +2340,36 @@ func (this *ServerDAO) UpdateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64 // RenewServerTrafficLimitStatus 根据限流配置更新网站的流量限制状态 func (this *ServerDAO) RenewServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error { + if serverId <= 0 { + return nil + } + if !trafficLimitConfig.IsOn { if isUpdatingConfig { + var oldStatus = &serverconfigs.TrafficLimitStatus{} + trafficLimitStatus, err := this.Query(tx). + Pk(serverId). + Result("trafficLimitStatus"). + FindJSONCol() + if err != nil { + return err + } + if IsNotNull(trafficLimitStatus) { + err = json.Unmarshal(trafficLimitStatus, oldStatus) + if err != nil { + return err + } + if oldStatus.PlanId == 0 /** 说明是网站自行设置的限制 **/ { + err = this.Query(tx). + Pk(serverId). + Set("trafficLimitStatus", dbs.SQL("NULL")). + UpdateQuickly() + if err != nil { + return err + } + } + } + return this.NotifyUpdate(tx, serverId) } return nil @@ -2470,7 +2480,9 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, serverId int64 if err != nil { return err } - if len(oldStatus.UntilDay) > 0 && oldStatus.UntilDay >= day /** 如果已经限制,且比当前日期长,则无需重复 **/ { + if len(oldStatus.UntilDay) > 0 && + oldStatus.UntilDay >= day /** 如果已经限制,且比当前日期长,则无需重复 **/ && + oldStatus.PlanId == planId /** 套餐无变化 **/ { // no need to change return nil } diff --git a/internal/rpc/services/service_plan_community.go b/internal/rpc/services/service_plan_community.go index 1cd4db1f..6059cdac 100644 --- a/internal/rpc/services/service_plan_community.go +++ b/internal/rpc/services/service_plan_community.go @@ -1,6 +1,5 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. //go:build !plus -// +build !plus package services @@ -53,3 +52,8 @@ func (this *PlanService) SortPlans(ctx context.Context, req *pb.SortPlansRequest func (this *PlanService) FindAllAvailablePlans(ctx context.Context, req *pb.FindAllAvailablePlansRequest) (*pb.FindAllAvailablePlansResponse, error) { return nil, this.NotImplementedYet() } + +// FindAllAvailableBasicPlans 列出所有可用的套餐的基本信息 +func (this *PlanService) FindAllAvailableBasicPlans(ctx context.Context, req *pb.FindAllAvailableBasicPlansRequest) (*pb.FindAllAvailableBasicPlansResponse, error) { + return nil, this.NotImplementedYet() +} diff --git a/internal/setup/sql.json b/internal/setup/sql.json index 5363c3ae..31434d83 100644 --- a/internal/setup/sql.json +++ b/internal/setup/sql.json @@ -111485,7 +111485,7 @@ "name": "edgePlans", "engine": "InnoDB", "charset": "utf8mb4_general_ci", - "definition": "CREATE TABLE `edgePlans` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n `name` varchar(255) DEFAULT NULL COMMENT '套餐名',\n `description` varchar(255) DEFAULT NULL COMMENT '套餐简介',\n `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n `trafficLimit` json DEFAULT NULL COMMENT '流量限制',\n `features` json DEFAULT NULL COMMENT '允许的功能',\n `hasFullFeatures` tinyint(1) unsigned DEFAULT '1' COMMENT '是否有完整的功能',\n `trafficPrice` json DEFAULT NULL COMMENT '流量价格设定',\n `bandwidthPrice` json DEFAULT NULL COMMENT '带宽价格',\n `monthlyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '月付',\n `seasonallyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '季付',\n `yearlyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '年付',\n `priceType` varchar(32) DEFAULT NULL COMMENT '价格类型',\n `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n `totalServers` int(11) unsigned DEFAULT '1' COMMENT '可以绑定的网站数量',\n `totalServerNamesPerServer` int(255) unsigned DEFAULT '0' COMMENT '每个网站可以绑定的域名数量',\n `totalServerNames` int(255) unsigned DEFAULT '0' COMMENT '总域名数量',\n `monthlyRequests` bigint(20) unsigned DEFAULT '0' COMMENT '每月访问量额度',\n `dailyRequests` bigint(20) unsigned DEFAULT '0' COMMENT '每日访问量额度',\n `dailyWebsocketConnections` bigint(20) unsigned DEFAULT '0' COMMENT '每日Websocket连接数',\n `monthlyWebsocketConnections` bigint(20) unsigned DEFAULT '0' COMMENT '每月Websocket连接数',\n PRIMARY KEY (`id`),\n KEY `state` (`state`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户套餐'", + "definition": "CREATE TABLE `edgePlans` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n `name` varchar(255) DEFAULT NULL COMMENT '套餐名',\n `description` varchar(255) DEFAULT NULL COMMENT '套餐简介',\n `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n `trafficLimit` json DEFAULT NULL COMMENT '流量限制',\n `bandwidthLimitPerNode` json DEFAULT NULL COMMENT '单节点带宽限制',\n `features` json DEFAULT NULL COMMENT '允许的功能',\n `hasFullFeatures` tinyint(1) unsigned DEFAULT '1' COMMENT '是否有完整的功能',\n `trafficPrice` json DEFAULT NULL COMMENT '流量价格设定',\n `bandwidthPrice` json DEFAULT NULL COMMENT '带宽价格',\n `monthlyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '月付',\n `seasonallyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '季付',\n `yearlyPrice` decimal(12,2) unsigned DEFAULT '0.00' COMMENT '年付',\n `priceType` varchar(32) DEFAULT NULL COMMENT '价格类型',\n `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n `totalServers` int(11) unsigned DEFAULT '1' COMMENT '可以绑定的网站数量',\n `totalServerNamesPerServer` int(255) unsigned DEFAULT '0' COMMENT '每个网站可以绑定的域名数量',\n `totalServerNames` int(255) unsigned DEFAULT '0' COMMENT '总域名数量',\n `monthlyRequests` bigint(20) unsigned DEFAULT '0' COMMENT '每月访问量额度',\n `dailyRequests` bigint(20) unsigned DEFAULT '0' COMMENT '每日访问量额度',\n `dailyWebsocketConnections` bigint(20) unsigned DEFAULT '0' COMMENT '每日Websocket连接数',\n `monthlyWebsocketConnections` bigint(20) unsigned DEFAULT '0' COMMENT '每月Websocket连接数',\n PRIMARY KEY (`id`),\n KEY `state` (`state`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户套餐'", "fields": [ { "name": "id", @@ -111511,6 +111511,10 @@ "name": "trafficLimit", "definition": "json COMMENT '流量限制'" }, + { + "name": "bandwidthLimitPerNode", + "definition": "json COMMENT '单节点带宽限制'" + }, { "name": "features", "definition": "json COMMENT '允许的功能'" @@ -111592,6 +111596,108 @@ ], "records": [] }, + { + "name": "edgePostCategories", + "engine": "InnoDB", + "charset": "utf8mb4_general_ci", + "definition": "CREATE TABLE `edgePostCategories` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `name` varchar(255) DEFAULT NULL COMMENT '分类名称',\n `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n `code` varchar(255) DEFAULT NULL COMMENT '代号',\n `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '分类状态',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类'", + "fields": [ + { + "name": "id", + "definition": "int(11) unsigned auto_increment COMMENT 'ID'" + }, + { + "name": "name", + "definition": "varchar(255) COMMENT '分类名称'" + }, + { + "name": "isOn", + "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用'" + }, + { + "name": "code", + "definition": "varchar(255) COMMENT '代号'" + }, + { + "name": "order", + "definition": "int(11) unsigned DEFAULT '0' COMMENT '排序'" + }, + { + "name": "state", + "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '分类状态'" + } + ], + "indexes": [ + { + "name": "PRIMARY", + "definition": "UNIQUE KEY `PRIMARY` (`id`) USING BTREE" + } + ], + "records": [] + }, + { + "name": "edgePosts", + "engine": "InnoDB", + "charset": "utf8mb4_general_ci", + "definition": "CREATE TABLE `edgePosts` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `categoryId` int(11) unsigned DEFAULT '0' COMMENT '文章分类',\n `type` varchar(255) DEFAULT NULL COMMENT '类型:normal, url',\n `url` varchar(255) DEFAULT NULL COMMENT 'URL',\n `subject` varchar(255) DEFAULT NULL COMMENT '标题',\n `body` longtext COMMENT '内容',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `isPublished` tinyint(1) unsigned DEFAULT '0' COMMENT '是否已发布',\n `publishedAt` bigint(11) unsigned DEFAULT '0' COMMENT '发布时间',\n `productCode` varchar(64) DEFAULT NULL COMMENT '产品代号',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n PRIMARY KEY (`id`),\n KEY `categoryId` (`categoryId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章管理'", + "fields": [ + { + "name": "id", + "definition": "int(11) unsigned auto_increment COMMENT 'ID'" + }, + { + "name": "categoryId", + "definition": "int(11) unsigned DEFAULT '0' COMMENT '文章分类'" + }, + { + "name": "type", + "definition": "varchar(255) COMMENT '类型:normal, url'" + }, + { + "name": "url", + "definition": "varchar(255) COMMENT 'URL'" + }, + { + "name": "subject", + "definition": "varchar(255) COMMENT '标题'" + }, + { + "name": "body", + "definition": "longtext COMMENT '内容'" + }, + { + "name": "createdAt", + "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'" + }, + { + "name": "isPublished", + "definition": "tinyint(1) unsigned DEFAULT '0' COMMENT '是否已发布'" + }, + { + "name": "publishedAt", + "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '发布时间'" + }, + { + "name": "productCode", + "definition": "varchar(64) COMMENT '产品代号'" + }, + { + "name": "state", + "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '状态'" + } + ], + "indexes": [ + { + "name": "PRIMARY", + "definition": "UNIQUE KEY `PRIMARY` (`id`) USING BTREE" + }, + { + "name": "categoryId", + "definition": "KEY `categoryId` (`categoryId`) USING BTREE" + } + ], + "records": [] + }, { "name": "edgeProviders", "engine": "InnoDB",