Compare commits

...

60 Commits

Author SHA1 Message Date
刘祥超
2888634fb0 将版本号修改为1.3.1 2023-11-23 17:24:09 +08:00
刘祥超
94defc3e0c 优化SSH认证sudo设置 2023-11-23 16:12:52 +08:00
刘祥超
9089ed2657 DNSPod改名为腾讯云DNSPod/DNSPod 支持腾讯云API密钥 2023-11-23 15:15:11 +08:00
刘祥超
b60bb5f6da 提交SQL 2023-11-19 09:11:07 +08:00
刘祥超
ff4ea41963 节点配置中增加节点IP信息 2023-11-18 12:09:47 +08:00
刘祥超
b7dccad449 实现用户系统手机号码绑定和登录(商业版) 2023-11-17 11:51:29 +08:00
刘祥超
7fead214d4 更新SQL 2023-11-15 19:10:18 +08:00
刘祥超
d9590ec605 创建反向代理时默认不自动重试50X/源站支持404内容自动重试其他源站 2023-11-15 19:05:43 +08:00
刘祥超
20b936580f 版本号修改为1.3.0 2023-11-14 14:47:32 +08:00
刘祥超
b7b43bc31f 限制访问日志中域名能写入的最大长度 2023-11-13 17:12:11 +08:00
刘祥超
6fd4f26755 自定义页面增加例外URL和限制URL设置 2023-11-13 10:46:12 +08:00
刘祥超
f15d114708 自定义页面增加“跳转URL”功能 2023-11-10 16:36:09 +08:00
刘祥超
fc24195b55 增加访问日志中域名长度 2023-11-10 09:56:17 +08:00
刘祥超
ed5de57244 去除一处多余的日志 2023-11-07 17:34:09 +08:00
刘祥超
4ce347738f 修复无法将OSS源站修改为http/https源站的问题 2023-11-04 08:28:08 +08:00
刘祥超
f6e725781c 优化节点阈值设置 2023-11-03 11:20:47 +08:00
刘祥超
55d70418cc 节点健康检查失败时增加节点名称和节点IP提示 2023-11-03 09:54:42 +08:00
刘祥超
7f5b070e36 优化商业版验证 2023-11-02 17:20:12 +08:00
刘祥超
993c7ee822 上传域名统计数据时限制域名长度不能超过64位 2023-11-02 17:19:56 +08:00
刘祥超
b5bb4e0df9 更新数据库 2023-10-30 19:04:23 +08:00
刘祥超
9f120fd0e0 访问日志存储策略增加“停止默认数据库存储”选项 2023-10-30 19:03:39 +08:00
刘祥超
77d614c9ea 实现网络数据包相关统计(商业版本) 2023-10-26 17:17:43 +08:00
刘祥超
531ec3c55d 优化域名解析文字提示 2023-10-17 15:54:08 +08:00
刘祥超
0d6c064194 将版本号修改为1.2.11 2023-10-17 13:49:39 +08:00
刘祥超
180e86c643 修复消息通知不能指定集群的Bug 2023-10-17 13:49:23 +08:00
刘祥超
86b04b2b6b 将临时的1.2.9.1升级程序版本号修改为1.2.10 2023-10-15 15:10:36 +08:00
刘祥超
7a5ec79ace 将版本号修改为1.2.10 2023-10-15 13:34:18 +08:00
刘祥超
7290ffd2cd 取消默认反向代理默认的50X重试 2023-10-15 09:40:39 +08:00
刘祥超
2f361c5bcc 优化消息任务相关代码 2023-10-15 09:39:46 +08:00
刘祥超
500d72aaf3 WAF记录IP动作中IP名单如果为空时,默认为全局黑名单 2023-10-15 09:34:20 +08:00
刘祥超
9fc391d1e8 删除不必要的代码 2023-10-14 18:15:54 +08:00
刘祥超
c86e3e2047 优化消息通知相关代码 2023-10-14 17:16:08 +08:00
刘祥超
7e72a90f53 优化消息发送相关代码/删除监控相关代码 2023-10-12 20:11:21 +08:00
刘祥超
7692fed38d 支持批量复制WAF设置 2023-10-09 19:52:51 +08:00
刘祥超
bdd7d2a181 申请证书任务列表区分管理员和用户 2023-10-09 16:18:32 +08:00
刘祥超
118c3f79e4 证书列表区分管理员和用户证书 2023-10-09 15:54:00 +08:00
刘祥超
804a33a002 访问日志列表搜索增加请求来源查询语法:referer:example.com 2023-10-08 17:52:53 +08:00
刘祥超
fe00588039 集群设置中增加“自动调节系统参数”选项 2023-10-08 15:08:28 +08:00
刘祥超
67aac200a7 修复常用网站、常用集群查询可能因为updatedAt过大导致的SQL错误 2023-09-22 16:41:44 +08:00
刘祥超
3e01ad4b68 节点配置中对父级节点进行排序,以保证查找的稳定性 2023-09-22 11:55:47 +08:00
刘祥超
b39690484e 将升级程序中的1.2.10改成1.2.9.1,方便在测试版本中也能升级 2023-09-18 17:02:54 +08:00
刘祥超
31a69ecb12 将全局设置的TCP相关设置移到“集群设置--网站设置”中 2023-09-18 16:55:45 +08:00
刘祥超
94b95beadf 将全局的通用设置--域名审核设置移到“集群设置--网站设置”中 2023-09-18 16:09:11 +08:00
刘祥超
6143f08cf2 IP名单删除任务完成后删除任务 2023-09-14 09:12:19 +08:00
刘祥超
73a5814fd6 版本号修改为1.2.9 2023-09-13 17:37:41 +08:00
刘祥超
448152d5c2 优化删除IP名单时操作 2023-09-13 17:16:00 +08:00
刘祥超
eedb3fb338 将节点版本号修改为1.2.9 2023-09-12 15:03:00 +08:00
刘祥超
06f6f68f3a 增加自动升级一处WAF规则 2023-09-12 14:59:07 +08:00
刘祥超
903e524e80 优化访客IP地址设置 2023-09-07 18:03:28 +08:00
刘祥超
fa6b4fcaee 套餐增加请求数(日/月)限制 2023-09-07 11:46:03 +08:00
刘祥超
67cc8e515f 修复一个测试用例 2023-09-06 18:19:25 +08:00
刘祥超
fa29817920 统计带宽计算增加最小样本数 2023-09-06 18:14:08 +08:00
刘祥超
794c3bc132 优化套餐升级程序 2023-09-06 18:01:41 +08:00
刘祥超
9e481d31ac 重新实现套餐相关功能 2023-09-06 16:30:47 +08:00
刘祥超
4ebc03af75 调用自定义HTTP DNS时增加action(值为GetDomains) 2023-08-28 16:28:08 +08:00
刘祥超
80e2face67 更新Agent IP库 2023-08-27 11:58:14 +08:00
刘祥超
815a5187d5 反向代理增加是否重试50X选项,默认为启用 2023-08-20 15:49:34 +08:00
刘祥超
1d7bc42fba 修复节点状态监控中磁盘空间可能为0的问题 2023-08-18 16:01:24 +08:00
刘祥超
1eb9cca793 将WAF策略中的默认省份封禁提示内容长度从255修改为65535 2023-08-14 12:54:11 +08:00
刘祥超
8766f5b1a9 修改版本号为1.2.8 2023-08-14 12:24:29 +08:00
114 changed files with 16438 additions and 2823 deletions

View File

@@ -12,5 +12,5 @@ dbs:
fields:
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled" ]
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled", "enableHTTP2", "retry50X", "retry40X", "autoSystemTuning", "disableDefaultDB" ]

View File

@@ -1,3 +1,7 @@
#!/usr/bin/env bash
go run `dirname $0`/../cmd/sql-dump/main.go -dir=`dirname $0`
# generate 'internal/setup/sql.json' file
CWD="$(dirname "$0")"
go run "${CWD}"/../cmd/sql-dump/main.go -dir="${CWD}"

View File

@@ -1,12 +1,14 @@
package teaconst
const (
Version = "1.2.7"
Version = "1.3.1"
ProductName = "Edge API"
ProcessName = "edge-api"
ProductNameZH = "Edge"
GlobalProductName = "GoEdge"
Role = "api"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
@@ -18,7 +20,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "1.2.7"
NodeVersion = "1.3.1"
// SQLVersion SQL版本号
SQLVersion = "11"

View File

@@ -107,9 +107,17 @@ func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) err
}
// CountAllEnabledACMETasks 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string) (int64, error) {
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userOnly bool) (int64, error) {
var query = this.Query(tx)
query.Attr("userId", userId) // 这个条件必须加上
if userId > 0 {
query.Attr("userId", userId)
} else {
if userOnly {
query.Gt("userId", 0)
} else {
query.Attr("userId", 0)
}
}
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -139,9 +147,17 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAv
}
// ListEnabledACMETasks 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, offset int64, size int64) (result []*ACMETask, err error) {
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userOnly bool, offset int64, size int64) (result []*ACMETask, err error) {
var query = this.Query(tx)
query.Attr("userId", userId) // 这个条件必须加上
if userId > 0 {
query.Attr("userId", userId)
} else {
if userOnly {
query.Gt("userId", 0)
} else {
query.Attr("userId", 0)
}
}
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -229,8 +245,8 @@ func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId
return err
}
// CheckACMETask 检查权限
func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, userId int64, acmeTaskId int64) (bool, error) {
// CheckUserACMETask 检查用户权限
func (this *ACMETaskDAO) CheckUserACMETask(tx *dbs.Tx, userId int64, acmeTaskId int64) (bool, error) {
var query = this.Query(tx)
if userId > 0 {
query.Attr("userId", userId)
@@ -242,6 +258,15 @@ func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, userId int64, acmeTaskId int6
Exist()
}
// FindACMETaskUserId 查找任务所属用户ID
func (this *ACMETaskDAO) FindACMETaskUserId(tx *dbs.Tx, taskId int64) (userId int64, err error) {
return this.Query(tx).
Pk(taskId).
Result("userId").
FindInt64Col(0)
}
// UpdateACMETaskCert 设置任务关联的证书
func (this *ACMETaskDAO) UpdateACMETaskCert(tx *dbs.Tx, taskId int64, certId int64) error {
if taskId <= 0 {

View File

@@ -0,0 +1,6 @@
package authority_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -2,6 +2,18 @@ package authority
import "github.com/iwind/TeaGo/dbs"
const (
AuthorityKeyField_Id dbs.FieldName = "id" // ID
AuthorityKeyField_Value dbs.FieldName = "value" // Key值
AuthorityKeyField_DayFrom dbs.FieldName = "dayFrom" // 开始日期
AuthorityKeyField_DayTo dbs.FieldName = "dayTo" // 结束日期
AuthorityKeyField_Hostname dbs.FieldName = "hostname" // Hostname
AuthorityKeyField_MacAddresses dbs.FieldName = "macAddresses" // MAC地址
AuthorityKeyField_UpdatedAt dbs.FieldName = "updatedAt" // 创建/修改时间
AuthorityKeyField_Company dbs.FieldName = "company" // 公司组织
AuthorityKeyField_RequestCode dbs.FieldName = "requestCode" // 申请码
)
// AuthorityKey 企业版认证信息
type AuthorityKey struct {
Id uint32 `field:"id"` // ID
@@ -12,17 +24,19 @@ type AuthorityKey struct {
MacAddresses dbs.JSON `field:"macAddresses"` // MAC地址
UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间
Company string `field:"company"` // 公司组织
RequestCode string `field:"requestCode"` // 申请码
}
type AuthorityKeyOperator struct {
Id interface{} // ID
Value interface{} // Key值
DayFrom interface{} // 开始日期
DayTo interface{} // 结束日期
Hostname interface{} // Hostname
MacAddresses interface{} // MAC地址
UpdatedAt interface{} // 创建/修改时间
Company interface{} // 公司组织
Id any // ID
Value any // Key值
DayFrom any // 开始日期
DayTo any // 结束日期
Hostname any // Hostname
MacAddresses any // MAC地址
UpdatedAt any // 创建/修改时间
Company any // 公司组织
RequestCode any // 申请码
}
func NewAuthorityKeyOperator() *AuthorityKeyOperator {

View File

@@ -245,7 +245,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
return err
}
fields := map[string]interface{}{}
var fields = map[string]any{}
fields["serverId"] = accessLog.ServerId
fields["nodeId"] = accessLog.NodeId
fields["status"] = accessLog.Status
@@ -265,7 +265,11 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
fields["remoteAddr"] = accessLog.RemoteAddr
}
if tableDef.HasDomain {
fields["domain"] = accessLog.Host
if len(accessLog.Host) > 128 {
fields["domain"] = accessLog.Host[:128]
} else {
fields["domain"] = accessLog.Host
}
}
content, err := json.Marshal(accessLog)
@@ -461,6 +465,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var protoReg = regexp.MustCompile(`proto:(\S+)`)
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
var methodReg = regexp.MustCompile(`(?:method|requestMethod):(\S+)`)
var refererReg = regexp.MustCompile(`referer:(\S+)`)
var count = len(tableQueries)
var wg = &sync.WaitGroup{}
@@ -613,6 +618,11 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var matches = methodReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.requestMethod')=:keyword").
Param("keyword", strings.ToUpper(matches[1]))
} else if refererReg.MatchString(keyword) {
isSpecialKeyword = true
var matches = refererReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.referer') LIKE :keyword").
Param("keyword", dbutils.QuoteLike(matches[1]))
}
if !isSpecialKeyword {
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
@@ -857,8 +867,4 @@ func (this *HTTPAccessLogDAO) SetupQueue() {
oldAccessLogQueue = accessLogQueue
accessLogQueue = make(chan *pb.HTTPAccessLog, config.MaxLength)
}
if Tea.IsTesting() {
remotelogs.Println("HTTP_ACCESS_LOG_QUEUE", "change queue "+string(configJSON))
}
}

View File

@@ -239,7 +239,7 @@ func (this *HTTPAccessLogManager) FindLastTable(db *dbs.DB, day string, force bo
// CreateTable 创建访问日志表格
func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error {
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(255) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
if err != nil {
if CheckSQLErrCode(err, 1050) { // Error 1050: Table 'xxx' already exists
return nil

View File

@@ -107,7 +107,7 @@ func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAndOnPolicies(tx *dbs.Tx) (res
}
// CreatePolicy 创建策略
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool) (policyId int64, err error) {
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool) (policyId int64, err error) {
var op = NewHTTPAccessLogPolicyOperator()
op.Name = name
op.Type = policyType
@@ -120,12 +120,13 @@ func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policy
op.IsPublic = isPublic
op.IsOn = true
op.FirewallOnly = firewallOnly
op.DisableDefaultDB = disableDefaultDB
op.State = HTTPAccessLogPolicyStateEnabled
return this.SaveInt64(tx, op)
}
// UpdatePolicy 修改策略
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, isOn bool) error {
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool, isOn bool) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
@@ -159,6 +160,7 @@ func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, nam
op.IsPublic = isPublic
op.FirewallOnly = firewallOnly
op.DisableDefaultDB = disableDefaultDB
op.IsOn = isOn
return this.Save(tx, op)
}

View File

@@ -2,39 +2,59 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPAccessLogPolicyField_Id dbs.FieldName = "id" // ID
HTTPAccessLogPolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPAccessLogPolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPAccessLogPolicyField_UserId dbs.FieldName = "userId" // 用户ID
HTTPAccessLogPolicyField_State dbs.FieldName = "state" // 状态
HTTPAccessLogPolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPAccessLogPolicyField_Name dbs.FieldName = "name" // 名称
HTTPAccessLogPolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPAccessLogPolicyField_Type dbs.FieldName = "type" // 存储类型
HTTPAccessLogPolicyField_Options dbs.FieldName = "options" // 存储选项
HTTPAccessLogPolicyField_Conds dbs.FieldName = "conds" // 请求条件
HTTPAccessLogPolicyField_IsPublic dbs.FieldName = "isPublic" // 是否为公用
HTTPAccessLogPolicyField_FirewallOnly dbs.FieldName = "firewallOnly" // 是否只记录防火墙相关
HTTPAccessLogPolicyField_Version dbs.FieldName = "version" // 版本号
HTTPAccessLogPolicyField_DisableDefaultDB dbs.FieldName = "disableDefaultDB" // 是否停止默认数据库存储
)
// HTTPAccessLogPolicy 访问日志策略
type HTTPAccessLogPolicy struct {
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Name string `field:"name"` // 名称
IsOn bool `field:"isOn"` // 是否启用
Type string `field:"type"` // 存储类型
Options dbs.JSON `field:"options"` // 存储选项
Conds dbs.JSON `field:"conds"` // 请求条件
IsPublic bool `field:"isPublic"` // 是否为公用
FirewallOnly uint8 `field:"firewallOnly"` // 是否只记录防火墙相关
Version uint32 `field:"version"` // 版本号
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Name string `field:"name"` // 名称
IsOn bool `field:"isOn"` // 是否启用
Type string `field:"type"` // 存储类型
Options dbs.JSON `field:"options"` // 存储选项
Conds dbs.JSON `field:"conds"` // 请求条件
IsPublic bool `field:"isPublic"` // 是否为公用
FirewallOnly uint8 `field:"firewallOnly"` // 是否只记录防火墙相关
Version uint32 `field:"version"` // 版本号
DisableDefaultDB bool `field:"disableDefaultDB"` // 是否停止默认数据库存储
}
type HTTPAccessLogPolicyOperator struct {
Id interface{} // ID
TemplateId interface{} // 模版ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
State interface{} // 状态
CreatedAt interface{} // 创建时间
Name interface{} // 名称
IsOn interface{} // 是否启用
Type interface{} // 存储类型
Options interface{} // 存储选项
Conds interface{} // 请求条件
IsPublic interface{} // 是否为公用
FirewallOnly interface{} // 是否只记录防火墙相关
Version interface{} // 版本号
Id any // ID
TemplateId any // 模版ID
AdminId any // 管理员ID
UserId any // 用户ID
State any // 状态
CreatedAt any // 创建时间
Name any // 名称
IsOn any // 是否启用
Type any // 存储类型
Options any // 存储选项
Conds any // 请求条件
IsPublic any // 是否为公用
FirewallOnly any // 是否只记录防火墙相关
Version any // 版本号
DisableDefaultDB any // 是否停止默认数据库存储
}
func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator {

View File

@@ -279,6 +279,31 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
return this.NotifyUpdate(tx, policyId)
}
// UpdateFirewallPolicyInboundRegion 修改入站封禁区域设置
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundRegion(tx *dbs.Tx, policyId int64, regionConfig *firewallconfigs.HTTPFirewallRegionConfig) error {
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
inboundJSON, err := this.Query(tx).
Pk(policyId).
Result("inbound").
FindJSONCol()
if err != nil {
return err
}
if IsNotNull(inboundJSON) {
err = json.Unmarshal(inboundJSON, inboundConfig)
if err != nil {
return err
}
}
inboundConfig.Region = regionConfig
newInboundJSON, err := json.Marshal(inboundConfig)
if err != nil {
return err
}
return this.UpdateFirewallPolicyInbound(tx, policyId, newInboundJSON)
}
// UpdateFirewallPolicy 修改策略
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
policyId int64,

View File

@@ -104,7 +104,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
return nil, err
}
for _, setRef := range setRefs {
setConfig, err := SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, setRef.SetId)
setConfig, err := SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, setRef.SetId, forNode)
if err != nil {
return nil, err
}

View File

@@ -84,7 +84,7 @@ func (this *HTTPFirewallRuleSetDAO) FindHTTPFirewallRuleSetName(tx *dbs.Tx, id i
}
// ComposeFirewallRuleSet 组合配置
func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int64) (*firewallconfigs.HTTPFirewallRuleSet, error) {
func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int64, forNode bool) (*firewallconfigs.HTTPFirewallRuleSet, error) {
set, err := this.FindEnabledHTTPFirewallRuleSet(tx, setId)
if err != nil {
return nil, err
@@ -92,7 +92,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
if set == nil {
return nil, nil
}
config := &firewallconfigs.HTTPFirewallRuleSet{}
var config = &firewallconfigs.HTTPFirewallRuleSet{}
config.Id = int64(set.Id)
config.IsOn = set.IsOn
config.Name = set.Name
@@ -102,7 +102,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.IgnoreLocal = set.IgnoreLocal == 1
if IsNotNull(set.Rules) {
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{}
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal(set.Rules, &ruleRefs)
if err != nil {
return nil, err
@@ -128,6 +128,29 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.Actions = actionConfigs
}
// 检查各个选项
for _, actionConfig := range actionConfigs {
if actionConfig.Code == firewallconfigs.HTTPFirewallActionRecordIP { // 记录IP动作
if actionConfig.Options != nil {
var ipListId = actionConfig.Options.GetInt64("ipListId")
if ipListId <= 0 { // default list id
if forNode {
actionConfig.Options["ipListId"] = firewallconfigs.GlobalListId
}
actionConfig.Options["ipListIsDeleted"] = false
} else {
exists, err := SharedIPListDAO.ExistsEnabledIPList(tx, ipListId)
if err != nil {
return nil, err
}
if !exists {
actionConfig.Options["ipListIsDeleted"] = true
}
}
}
}
}
return config, nil
}
@@ -212,6 +235,28 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, r
FindInt64Col(0)
}
// FindAllEnabledRuleSetIdsWithIPListId 根据IP名单ID查找对应动作的WAF规则集
func (this *HTTPFirewallRuleSetDAO) FindAllEnabledRuleSetIdsWithIPListId(tx *dbs.Tx, ipListId int64) (setIds []int64, err error) {
ones, err := this.Query(tx).
State(HTTPFirewallRuleStateEnabled).
Where("JSON_CONTAINS(actions, :jsonQuery)").
Param("jsonQuery", maps.Map{
"code": firewallconfigs.HTTPFirewallActionRecordIP,
"options": maps.Map{
"ipListId": ipListId,
},
}.AsJSON()).
ResultPk().
FindAll()
if err != nil {
return nil, err
}
for _, one := range ones {
setIds = append(setIds, int64(one.(*HTTPFirewallRuleSet).Id))
}
return
}
// CheckUserRuleSet 检查用户
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)

View File

@@ -77,7 +77,7 @@ func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, e
}
// CreatePage 创建Page
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) (pageId int64, err error) {
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType serverconfigs.HTTPPageBodyType, url string, body string, newStatus int, exceptURLPatterns []*shared.URLPattern, onlyURLPatterns []*shared.URLPattern) (pageId int64, err error) {
var op = NewHTTPPageOperator()
op.UserId = userId
op.IsOn = true
@@ -94,6 +94,29 @@ func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []strin
op.Url = url
op.Body = body
op.NewStatus = newStatus
{
if exceptURLPatterns == nil {
exceptURLPatterns = []*shared.URLPattern{}
}
exceptURLPatternsJSON, err := json.Marshal(exceptURLPatterns)
if err != nil {
return 0, err
}
op.ExceptURLPatterns = exceptURLPatternsJSON
}
{
if onlyURLPatterns == nil {
onlyURLPatterns = []*shared.URLPattern{}
}
onlyURLPatternsJSON, err := json.Marshal(onlyURLPatterns)
if err != nil {
return 0, err
}
op.OnlyURLPatterns = onlyURLPatternsJSON
}
err = this.Save(tx, op)
if err != nil {
return 0, err
@@ -103,7 +126,7 @@ func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []strin
}
// UpdatePage 修改Page
func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) error {
func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []string, bodyType serverconfigs.HTTPPageBodyType, url string, body string, newStatus int, exceptURLPatterns []*shared.URLPattern, onlyURLPatterns []*shared.URLPattern) error {
if pageId <= 0 {
return errors.New("invalid pageId")
}
@@ -126,6 +149,29 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
op.Url = url
op.Body = body
op.NewStatus = newStatus
{
if exceptURLPatterns == nil {
exceptURLPatterns = []*shared.URLPattern{}
}
exceptURLPatternsJSON, err := json.Marshal(exceptURLPatterns)
if err != nil {
return err
}
op.ExceptURLPatterns = exceptURLPatternsJSON
}
{
if onlyURLPatterns == nil {
onlyURLPatterns = []*shared.URLPattern{}
}
onlyURLPatternsJSON, err := json.Marshal(onlyURLPatterns)
if err != nil {
return err
}
op.OnlyURLPatterns = onlyURLPatternsJSON
}
err = this.Save(tx, op)
if err != nil {
return err
@@ -156,6 +202,14 @@ func (this *HTTPPageDAO) ClonePage(tx *dbs.Tx, fromPageId int64) (newPageId int6
op.Body = page.Body
op.BodyType = page.BodyType
op.State = page.State
if len(page.ExceptURLPatterns) > 0 {
op.ExceptURLPatterns = page.ExceptURLPatterns
}
if len(page.OnlyURLPatterns) > 0 {
op.OnlyURLPatterns = page.OnlyURLPatterns
}
return this.SaveInt64(tx, op)
}
@@ -179,7 +233,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
return nil, nil
}
config := &serverconfigs.HTTPPageConfig{}
var config = &serverconfigs.HTTPPageConfig{}
config.Id = int64(page.Id)
config.IsOn = page.IsOn
config.NewStatus = int(page.NewStatus)
@@ -188,7 +242,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
config.BodyType = page.BodyType
if len(page.BodyType) == 0 {
page.BodyType = shared.BodyTypeURL
page.BodyType = serverconfigs.HTTPPageBodyTypeURL
}
if len(page.StatusList) > 0 {
@@ -202,6 +256,28 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
}
}
if len(page.ExceptURLPatterns) > 0 {
var exceptURLPatterns = []*shared.URLPattern{}
err = json.Unmarshal(page.ExceptURLPatterns, &exceptURLPatterns)
if err != nil {
return nil, err
}
if len(exceptURLPatterns) > 0 {
config.ExceptURLPatterns = exceptURLPatterns
}
}
if len(page.OnlyURLPatterns) > 0 {
var onlyURLPatterns = []*shared.URLPattern{}
err = json.Unmarshal(page.OnlyURLPatterns, &onlyURLPatterns)
if err != nil {
return nil, err
}
if len(onlyURLPatterns) > 0 {
config.OnlyURLPatterns = onlyURLPatterns
}
}
if cacheMap != nil {
cacheMap.Put(cacheKey, config)
}

View File

@@ -2,33 +2,53 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPPageField_Id dbs.FieldName = "id" // ID
HTTPPageField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPPageField_UserId dbs.FieldName = "userId" // 用户ID
HTTPPageField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPPageField_StatusList dbs.FieldName = "statusList" // 状态列表
HTTPPageField_Url dbs.FieldName = "url" // 页面URL
HTTPPageField_NewStatus dbs.FieldName = "newStatus" // 新状态码
HTTPPageField_State dbs.FieldName = "state" // 状态
HTTPPageField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPPageField_Body dbs.FieldName = "body" // 页面内容
HTTPPageField_BodyType dbs.FieldName = "bodyType" // 内容类型
HTTPPageField_ExceptURLPatterns dbs.FieldName = "exceptURLPatterns" // 例外URL
HTTPPageField_OnlyURLPatterns dbs.FieldName = "onlyURLPatterns" // 限制URL
)
// HTTPPage 特殊页面
type HTTPPage struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
StatusList dbs.JSON `field:"statusList"` // 状态列表
Url string `field:"url"` // 页面URL
NewStatus int32 `field:"newStatus"` // 新状态码
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Body string `field:"body"` // 页面内容
BodyType string `field:"bodyType"` // 内容类型
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
StatusList dbs.JSON `field:"statusList"` // 状态列表
Url string `field:"url"` // 页面URL
NewStatus int32 `field:"newStatus"` // 新状态码
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Body string `field:"body"` // 页面内容
BodyType string `field:"bodyType"` // 内容类型
ExceptURLPatterns dbs.JSON `field:"exceptURLPatterns"` // 例外URL
OnlyURLPatterns dbs.JSON `field:"onlyURLPatterns"` // 限制URL
}
type HTTPPageOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
IsOn interface{} // 是否启用
StatusList interface{} // 状态列表
Url interface{} // 页面URL
NewStatus interface{} // 新状态码
State interface{} // 状态
CreatedAt interface{} // 创建时间
Body interface{} // 页面内容
BodyType interface{} // 内容类型
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
IsOn any // 是否启用
StatusList any // 状态列表
Url any // 页面URL
NewStatus any // 新状态码
State any // 状态
CreatedAt any // 创建时间
Body any // 页面内容
BodyType any // 内容类型
ExceptURLPatterns any // 例外URL
OnlyURLPatterns any // 限制URL
}
func NewHTTPPageOperator() *HTTPPageOperator {

View File

@@ -576,6 +576,7 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
IsOn: true,
Value: "${rawRemoteAddr}",
Type: serverconfigs.HTTPRemoteAddrTypeDefault,
}
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
if err != nil {

View File

@@ -11,6 +11,7 @@ import (
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -61,12 +62,16 @@ func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
}
// DisableIPList 禁用条目
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, id int64) error {
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, listId int64) error {
_, err := this.Query(tx).
Pk(id).
Pk(listId).
Set("state", IPListStateDisabled).
Update()
return err
if err != nil {
return err
}
return this.NotifyUpdate(tx, listId, NodeTaskTypeIPListDeleted+"@"+string(maps.Map{"listId": listId}.AsJSON()))
}
// FindEnabledIPList 查找启用中的条目
@@ -258,11 +263,35 @@ func (this *IPListDAO) ExistsEnabledIPList(tx *dbs.Tx, listId int64) (bool, erro
// NotifyUpdate 通知更新
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
// WAF策略中的
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
if err != nil {
return err
}
resultClusterIds := []int64{}
// 规则集动作中使用此名单的策略
ruleSetIds, err := SharedHTTPFirewallRuleSetDAO.FindAllEnabledRuleSetIdsWithIPListId(tx, listId)
if err != nil {
return err
}
for _, ruleSetId := range ruleSetIds {
ruleGroupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, ruleSetId)
if err != nil {
return err
}
if ruleGroupId > 0 {
policyId, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdWithRuleGroupId(tx, ruleGroupId)
if err != nil {
return err
}
if policyId > 0 && !lists.ContainsInt64(httpFirewallPolicyIds, policyId) {
httpFirewallPolicyIds = append(httpFirewallPolicyIds, policyId)
}
}
}
// 查找集群
var resultClusterIds = []int64{}
for _, policyId := range httpFirewallPolicyIds {
// 集群
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId)

View File

@@ -1,6 +1,7 @@
package models
import (
"errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"runtime"
@@ -27,7 +28,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -36,7 +37,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -45,7 +46,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -53,6 +54,17 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
}
}
func TestIPListDAO_NotifyUpdate(t *testing.T) {
dbs.NotifyReady()
var dao = NewIPListDAO()
var tx *dbs.Tx
err := dao.NotifyUpdate(tx, 104, NodeTaskTypeIPListDeleted)
if err != nil {
t.Fatal(err)
}
}
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
runtime.GOMAXPROCS(1)
@@ -65,4 +77,3 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
_, _ = dao.IncreaseVersion(tx)
}
}

View File

@@ -27,6 +27,8 @@ const (
type MessageType = string
const (
MessageTypeAll MessageType = "*"
// 这里的命名问题(首字母大写)为历史遗留问题,暂不修改
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
@@ -109,14 +111,17 @@ func (this *MessageDAO) FindEnabledMessage(tx *dbs.Tx, id int64) (*Message, erro
}
// CreateClusterMessage 创建集群消息
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, body, paramsJSON)
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, shortBody string, body string, paramsJSON []byte) error {
if len(shortBody) == 0 {
shortBody = body
}
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, shortBody, paramsJSON)
if err != nil {
return err
}
// 发送给媒介接收人
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, 0, 0, 0, messageType, subject, body)
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, clusterId, 0, 0, messageType, subject, body)
if err != nil {
return err
}

View File

@@ -12,7 +12,7 @@ func TestMessageDAO_CreateClusterMessage(t *testing.T) {
var tx *dbs.Tx
dao := NewMessageDAO()
err := dao.CreateClusterMessage(tx, nodeconfigs.NodeRoleNode, 1, "test", "error", "123", "123", []byte("456"))
err := dao.CreateClusterMessage(tx, nodeconfigs.NodeRoleNode, 1, "test", "error", "123", "123", "123", []byte("456"))
if err != nil {
t.Fatal(err)
}

View File

@@ -4,8 +4,6 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
const (
@@ -34,7 +32,7 @@ func init() {
})
}
// 启用条目
// EnableMessageMedia 启用条目
func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -43,7 +41,7 @@ func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableMessageMedia 禁用条目
func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -52,7 +50,7 @@ func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledMessageMedia 查找启用中的条目
func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*MessageMedia, error) {
result, err := this.Query(tx).
Pk(id).
@@ -64,7 +62,7 @@ func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*Mes
return result.(*MessageMedia), err
}
// 根据主键查找名称
// FindMessageMediaName 根据主键查找名称
func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -72,7 +70,7 @@ func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string,
FindStringCol("")
}
// 查询所有可用媒介
// FindAllEnabledMessageMedias 查询所有可用媒介
func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*MessageMedia, err error) {
_, err = this.Query(tx).
State(MessageMediaStateEnabled).
@@ -82,74 +80,3 @@ func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*
FindAll()
return
}
// 设置当前所有可用的媒介
func (this *MessageMediaDAO) UpdateMessageMedias(tx *dbs.Tx, mediaMaps []maps.Map) error {
// 新的媒介信息
mediaTypes := []string{}
for index, m := range mediaMaps {
order := len(mediaMaps) - index
mediaType := m.GetString("type")
mediaTypes = append(mediaTypes, mediaType)
name := m.GetString("name")
description := m.GetString("description")
userDescription := m.GetString("userDescription")
isOn := m.GetBool("isOn")
mediaId, err := this.Query(tx).
ResultPk().
Attr("type", mediaType).
FindInt64Col(0)
if err != nil {
return err
}
var op = NewMessageMediaOperator()
if mediaId > 0 {
op.Id = mediaId
}
op.Name = name
op.Type = mediaType
op.Description = description
op.UserDescription = userDescription
op.IsOn = isOn
op.Order = order
op.State = MessageMediaStateEnabled
err = this.Save(tx, op)
if err != nil {
return err
}
}
// 老的媒介信息
ones, err := this.Query(tx).
FindAll()
if err != nil {
return err
}
for _, one := range ones {
mediaType := one.(*MessageMedia).Type
if !lists.ContainsString(mediaTypes, mediaType) {
err := this.Query(tx).
Pk(one.(*MessageMedia).Id).
Set("state", MessageMediaStateDisabled).
UpdateQuickly()
if err != nil {
return err
}
}
}
return nil
}
// 根据类型查找媒介
func (this *MessageMediaDAO) FindEnabledMediaWithType(tx *dbs.Tx, mediaType string) (*MessageMedia, error) {
one, err := this.Query(tx).
Attr("type", mediaType).
State(MessageMediaStateEnabled).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*MessageMedia), nil
}

View File

@@ -98,24 +98,6 @@ func (this *MessageReceiverDAO) CreateReceiver(tx *dbs.Tx, role string, clusterI
return this.SaveInt64(tx, op)
}
// FindAllEnabledReceivers 查询接收人
func (this *MessageReceiverDAO) FindAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (result []*MessageReceiver, err error) {
query := this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
_, err = query.
Attr("role", role).
Attr("clusterId", clusterId).
Attr("nodeId", nodeId).
Attr("serverId", serverId).
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledReceivers 计算接收人数量
func (this *MessageReceiverDAO) CountAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (int64, error) {
query := this.Query(tx)
@@ -146,6 +128,8 @@ func (this *MessageReceiverDAO) FindEnabledBestFitReceivers(tx *dbs.Tx, role str
} else if nodeId > 0 {
query.Attr("nodeId", nodeId)
} else if clusterId > 0 {
query.Attr("serverId", 0)
query.Attr("nodeId", 0)
query.Attr("clusterId", clusterId)
}
_, err = query.

View File

@@ -1,30 +0,0 @@
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"testing"
)
func TestMessageReceiverDAO_FindEnabledBestFitReceivers(t *testing.T) {
var tx *dbs.Tx
{
receivers, err := NewMessageReceiverDAO().FindEnabledBestFitReceivers(tx, nodeconfigs.NodeRoleNode, 18, 1, 2, "*")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(receivers, t)
}
{
receivers, err := NewMessageReceiverDAO().FindEnabledBestFitReceivers(tx, nodeconfigs.NodeRoleNode, 30, 1, 2, "*")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(receivers, t)
}
}

View File

@@ -1,31 +1,19 @@
package models
import (
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type MessageTaskStatus = int
const (
MessageTaskStateEnabled = 1 // 已启用
MessageTaskStateDisabled = 0 // 已禁用
MessageTaskStatusNone MessageTaskStatus = 0 // 普通状态
MessageTaskStatusSending MessageTaskStatus = 1 // 发送中
MessageTaskStatusSuccess MessageTaskStatus = 2 // 发送成功
MessageTaskStatusFailed MessageTaskStatus = 3 // 发送失败
)
type MessageTaskDAO dbs.DAO
@@ -94,151 +82,6 @@ func (this *MessageTaskDAO) FindEnabledMessageTask(tx *dbs.Tx, id int64) (*Messa
return result.(*MessageTask), err
}
// CreateMessageTask 创建任务
func (this *MessageTaskDAO) CreateMessageTask(tx *dbs.Tx, recipientId int64, instanceId int64, user string, subject string, body string, isPrimary bool) (int64, error) {
if !teaconst.IsPlus {
return 0, nil
}
var hash = stringutil.Md5(types.String(recipientId) + "@" + types.String(instanceId) + "@" + user + "@" + subject + "@" + types.String(isPrimary))
recipientInstanceId, err := SharedMessageRecipientDAO.FindRecipientInstanceId(tx, recipientId)
if err != nil {
return 0, err
}
if recipientInstanceId > 0 {
hashLifeSeconds, err := SharedMessageMediaInstanceDAO.FindInstanceHashLifeSeconds(tx, recipientInstanceId)
if err != nil {
return 0, err
}
if hashLifeSeconds >= 0 { // 意味着此值如果小于0则不做判断
lastMessageAt, err := this.Query(tx).
Attr("hash", hash).
Result("createdAt").
DescPk().
FindInt64Col(0)
if err != nil {
return 0, err
}
// 对于同一个人N分钟内消息不重复发送
if hashLifeSeconds <= 0 {
hashLifeSeconds = 60
}
if lastMessageAt > 0 && time.Now().Unix()-lastMessageAt < int64(hashLifeSeconds) {
return 0, nil
}
}
}
var op = NewMessageTaskOperator()
op.RecipientId = recipientId
op.InstanceId = instanceId
op.Hash = hash
op.User = user
op.Subject = subject
op.Body = body
op.IsPrimary = isPrimary
op.Day = timeutil.Format("Ymd")
op.Status = MessageTaskStatusNone
op.State = MessageTaskStateEnabled
return this.SaveInt64(tx, op)
}
// FindSendingMessageTasks 查找需要发送的任务
func (this *MessageTaskDAO) FindSendingMessageTasks(tx *dbs.Tx, size int64) (result []*MessageTask, err error) {
if size <= 0 {
return nil, nil
}
_, err = this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", MessageTaskStatusNone).
Where("(recipientId=0 OR recipientId IN (SELECT id FROM "+SharedMessageRecipientDAO.Table+" WHERE state=1 AND isOn=1 AND (timeFrom IS NULL OR timeTo IS NULL OR :time BETWEEN timeFrom AND timeTo)))").
Param("time", timeutil.Format("H:i:s")).
Desc("isPrimary").
AscPk().
Limit(size).
Slice(&result).
FindAll()
return
}
// CountMessageTasksWithStatus 根据状态计算任务数量
func (this *MessageTaskDAO) CountMessageTasksWithStatus(tx *dbs.Tx, status MessageTaskStatus) (int64, error) {
return this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", status).
Count()
}
// ListMessageTasksWithStatus 根据状态列出单页任务
func (this *MessageTaskDAO) ListMessageTasksWithStatus(tx *dbs.Tx, status MessageTaskStatus, offset int64, size int64) (result []*MessageTask, err error) {
_, err = this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", status).
Desc("isPrimary").
AscPk().
Offset(offset).
Limit(size).
Slice(&result).
FindAll()
return
}
// UpdateMessageTaskStatus 设置发送的状态
func (this *MessageTaskDAO) UpdateMessageTaskStatus(tx *dbs.Tx, taskId int64, status MessageTaskStatus, result []byte) error {
if taskId <= 0 {
return errors.New("invalid taskId")
}
var op = NewMessageTaskOperator()
op.Id = taskId
op.Status = status
op.SentAt = time.Now().Unix()
if len(result) > 0 {
op.Result = result
}
return this.Save(tx, op)
}
// CreateMessageTasks 从集群、节点或者服务中创建任务
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, role nodeconfigs.NodeRole, clusterId int64, nodeId int64, serverId int64, messageType MessageType, subject string, body string) error {
if !teaconst.IsPlus {
return nil
}
receivers, err := SharedMessageReceiverDAO.FindEnabledBestFitReceivers(tx, role, clusterId, nodeId, serverId, messageType)
if err != nil {
return err
}
allRecipientIds := []int64{}
for _, receiver := range receivers {
if receiver.RecipientId > 0 {
allRecipientIds = append(allRecipientIds, int64(receiver.RecipientId))
} else if receiver.RecipientGroupId > 0 {
recipientIds, err := SharedMessageRecipientDAO.FindAllEnabledAndOnRecipientIdsWithGroup(tx, int64(receiver.RecipientGroupId))
if err != nil {
return err
}
allRecipientIds = append(allRecipientIds, recipientIds...)
}
}
sentMap := map[int64]bool{} // recipientId => bool 用来检查是否已经发送,防止重复发送给某个接收人
for _, recipientId := range allRecipientIds {
_, ok := sentMap[recipientId]
if ok {
continue
}
sentMap[recipientId] = true
_, err := this.CreateMessageTask(tx, recipientId, 0, "", subject, body, false)
if err != nil {
return err
}
}
return nil
}
// CleanExpiredMessageTasks 清理
func (this *MessageTaskDAO) CleanExpiredMessageTasks(tx *dbs.Tx, days int) error {
if days <= 0 {

View File

@@ -0,0 +1,14 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
)
// CreateMessageTasks 从集群、节点或者服务中创建任务
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, role nodeconfigs.NodeRole, clusterId int64, nodeId int64, serverId int64, messageType MessageType, subject string, body string) error {
return nil
}

View File

@@ -8,20 +8,6 @@ import (
"testing"
)
func TestMessageTaskDAO_FindSendingMessageTasks(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
tasks, err := models.NewMessageTaskDAO().FindSendingMessageTasks(tx, 100)
if err != nil {
t.Fatal(err)
}
t.Log(len(tasks), "tasks")
for _, task := range tasks {
t.Log("task:", task.Id, "recipient:", task.RecipientId)
}
}
func TestMessageTaskDAO_CleanExpiredMessageTasks(t *testing.T) {
var dao = models.NewMessageTaskDAO()
var tx *dbs.Tx

View File

@@ -1,215 +0,0 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
)
const (
MonitorNodeStateEnabled = 1 // 已启用
MonitorNodeStateDisabled = 0 // 已禁用
)
type MonitorNodeDAO dbs.DAO
func NewMonitorNodeDAO() *MonitorNodeDAO {
return dbs.NewDAO(&MonitorNodeDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeMonitorNodes",
Model: new(MonitorNode),
PkName: "id",
},
}).(*MonitorNodeDAO)
}
var SharedMonitorNodeDAO *MonitorNodeDAO
func init() {
dbs.OnReady(func() {
SharedMonitorNodeDAO = NewMonitorNodeDAO()
})
}
// EnableMonitorNode 启用条目
func (this *MonitorNodeDAO) EnableMonitorNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", MonitorNodeStateEnabled).
Update()
return err
}
// DisableMonitorNode 禁用条目
func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx).
Pk(nodeId).
Set("state", MonitorNodeStateDisabled).
Update()
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleMonitor, nodeId)
}
// FindEnabledMonitorNode 查找启用中的条目
func (this *MonitorNodeDAO) FindEnabledMonitorNode(tx *dbs.Tx, id int64) (*MonitorNode, error) {
result, err := this.Query(tx).
Pk(id).
Attr("state", MonitorNodeStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*MonitorNode), err
}
// FindMonitorNodeName 根据主键查找名称
func (this *MonitorNodeDAO) FindMonitorNodeName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
Result("name").
FindStringCol("")
}
// FindAllEnabledMonitorNodes 列出所有可用监控节点
func (this *MonitorNodeDAO) FindAllEnabledMonitorNodes(tx *dbs.Tx) (result []*MonitorNode, err error) {
_, err = this.Query(tx).
State(MonitorNodeStateEnabled).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledMonitorNodes 计算监控节点数量
func (this *MonitorNodeDAO) CountAllEnabledMonitorNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(MonitorNodeStateEnabled).
Count()
}
// ListEnabledMonitorNodes 列出单页的监控节点
func (this *MonitorNodeDAO) ListEnabledMonitorNodes(tx *dbs.Tx, offset int64, size int64) (result []*MonitorNode, err error) {
_, err = this.Query(tx).
State(MonitorNodeStateEnabled).
Offset(offset).
Limit(size).
Desc("order").
DescPk().
Slice(&result).
FindAll()
return
}
// CreateMonitorNode 创建监控节点
func (this *MonitorNodeDAO) CreateMonitorNode(tx *dbs.Tx, name string, description string, isOn bool) (nodeId int64, err error) {
uniqueId, err := this.GenUniqueId(tx)
if err != nil {
return 0, err
}
secret := rands.String(32)
err = NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleMonitor)
if err != nil {
return
}
var op = NewMonitorNodeOperator()
op.IsOn = isOn
op.UniqueId = uniqueId
op.Secret = secret
op.Name = name
op.Description = description
op.State = NodeStateEnabled
err = this.Save(tx, op)
if err != nil {
return
}
return types.Int64(op.Id), nil
}
// UpdateMonitorNode 修改监控节点
func (this *MonitorNodeDAO) UpdateMonitorNode(tx *dbs.Tx, nodeId int64, name string, description string, isOn bool) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
}
var op = NewMonitorNodeOperator()
op.Id = nodeId
op.Name = name
op.Description = description
op.IsOn = isOn
err := this.Save(tx, op)
return err
}
// FindEnabledMonitorNodeWithUniqueId 根据唯一ID获取节点信息
func (this *MonitorNodeDAO) FindEnabledMonitorNodeWithUniqueId(tx *dbs.Tx, uniqueId string) (*MonitorNode, error) {
result, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Attr("state", MonitorNodeStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*MonitorNode), err
}
// FindEnabledMonitorNodeIdWithUniqueId 根据唯一ID获取节点ID
func (this *MonitorNodeDAO) FindEnabledMonitorNodeIdWithUniqueId(tx *dbs.Tx, uniqueId string) (int64, error) {
return this.Query(tx).
Attr("uniqueId", uniqueId).
Attr("state", MonitorNodeStateEnabled).
ResultPk().
FindInt64Col(0)
}
// GenUniqueId 生成唯一ID
func (this *MonitorNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
for {
uniqueId := rands.HexString(32)
ok, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Exist()
if err != nil {
return "", err
}
if ok {
continue
}
return uniqueId, nil
}
}
// UpdateNodeStatus 更改节点状态
func (this *MonitorNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
if statusJSON == nil {
return nil
}
_, err := this.Query(tx).
Pk(nodeId).
Set("status", string(statusJSON)).
Update()
return err
}
// CountAllLowerVersionNodes 计算所有节点中低于某个版本的节点数量
func (this *MonitorNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(MonitorNodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).
Count()
}

View File

@@ -1,38 +0,0 @@
package models
import "github.com/iwind/TeaGo/dbs"
// MonitorNode 监控节点
type MonitorNode struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
UniqueId string `field:"uniqueId"` // 唯一ID
Secret string `field:"secret"` // 密钥
Name string `field:"name"` // 名称
Description string `field:"description"` // 描述
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
AdminId uint32 `field:"adminId"` // 管理员ID
Weight uint32 `field:"weight"` // 权重
Status dbs.JSON `field:"status"` // 运行状态
}
type MonitorNodeOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
UniqueId interface{} // 唯一ID
Secret interface{} // 密钥
Name interface{} // 名称
Description interface{} // 描述
Order interface{} // 排序
State interface{} // 状态
CreatedAt interface{} // 创建时间
AdminId interface{} // 管理员ID
Weight interface{} // 权重
Status interface{} // 运行状态
}
func NewMonitorNodeOperator() *MonitorNodeOperator {
return &MonitorNodeOperator{}
}

View File

@@ -126,7 +126,7 @@ func (this *NodeClusterDAO) FindAllEnableClusterIds(tx *dbs.Tx) (result []int64,
}
// CreateCluster 创建集群
func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string, grantId int64, installDir string, dnsDomainId int64, dnsName string, dnsTTL int32, cachePolicyId int64, httpFirewallPolicyId int64, systemServices map[string]maps.Map, globalServerConfig *serverconfigs.GlobalServerConfig, autoInstallNftables bool) (clusterId int64, err error) {
func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string, grantId int64, installDir string, dnsDomainId int64, dnsName string, dnsTTL int32, cachePolicyId int64, httpFirewallPolicyId int64, systemServices map[string]maps.Map, globalServerConfig *serverconfigs.GlobalServerConfig, autoInstallNftables bool, autoSystemTuning bool) (clusterId int64, err error) {
uniqueId, err := this.GenUniqueId(tx)
if err != nil {
return 0, err
@@ -189,6 +189,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
op.UniqueId = uniqueId
op.Secret = secret
op.AutoInstallNftables = autoInstallNftables
op.AutoSystemTuning = autoSystemTuning
op.State = NodeClusterStateEnabled
err = this.Save(tx, op)
if err != nil {
@@ -199,7 +200,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
}
// UpdateCluster 修改集群
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool, clockConfig *nodeconfigs.ClockConfig, autoRemoteStart bool, autoInstallTables bool, sshParams *nodeconfigs.SSHParams) error {
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool, clockConfig *nodeconfigs.ClockConfig, autoRemoteStart bool, autoInstallTables bool, sshParams *nodeconfigs.SSHParams, autoSystemTuning bool) error {
if clusterId <= 0 {
return errors.New("invalid clusterId")
}
@@ -226,6 +227,7 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
op.AutoRemoteStart = autoRemoteStart
op.AutoInstallNftables = autoInstallTables
op.AutoSystemTuning = autoSystemTuning
if sshParams != nil {
sshParamsJSON, err := json.Marshal(sshParams)
@@ -950,11 +952,12 @@ func (this *NodeClusterDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
// FindLatestNodeClusters 查询最近访问的集群
func (this *NodeClusterDAO) FindLatestNodeClusters(tx *dbs.Tx, size int64) (result []*NodeCluster, err error) {
itemTable := SharedLatestItemDAO.Table
itemType := LatestItemTypeCluster
var itemTable = SharedLatestItemDAO.Table
var itemType = LatestItemTypeCluster
_, err = this.Query(tx).
Result(this.Table+".id", this.Table+".name").
Join(SharedLatestItemDAO, dbs.QueryJoinRight, this.Table+".id="+itemTable+".itemId AND "+itemTable+".itemType='"+itemType+"'").
Where(itemTable + ".updatedAt<=UNIX_TIMESTAMP()"). // VERY IMPORTANT
Asc("CEIL((UNIX_TIMESTAMP() - " + itemTable + ".updatedAt) / (7 * 86400))"). // 优先一个星期以内的
Desc(itemTable + ".count").
State(NodeClusterStateEnabled).
@@ -1018,7 +1021,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx).
Pk(clusterId).
State(NodeClusterStateEnabled).
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables").
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables", "autoSystemTuning", "networkSecurity").
Find()
if err != nil || cluster == nil {
return nil, err
@@ -1266,6 +1269,57 @@ func (this *NodeClusterDAO) FindClusterHTTP3Policy(tx *dbs.Tx, clusterId int64,
return policy, nil
}
// UpdateClusterNetworkSecurityPolicy 修改网络安全策略设置
func (this *NodeClusterDAO) UpdateClusterNetworkSecurityPolicy(tx *dbs.Tx, clusterId int64, networkSecurityPolicy *nodeconfigs.NetworkSecurityPolicy) error {
if networkSecurityPolicy == nil {
networkSecurityPolicy = nodeconfigs.NewNetworkSecurityPolicy()
}
networkSecurityPolicyJSON, err := json.Marshal(networkSecurityPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("networkSecurity", networkSecurityPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyNetworkSecurityUpdate(tx, clusterId)
}
// FindClusterNetworkSecurityPolicy 查询网络安全策略设置
func (this *NodeClusterDAO) FindClusterNetworkSecurityPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.NetworkSecurityPolicy, error) {
var cacheKey = this.Table + ":FindClusterNetworkSecurityPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.NetworkSecurityPolicy), nil
}
}
networkSecurityPolicyJSON, err := this.Query(tx).
Pk(clusterId).
Result("networkSecurity").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(networkSecurityPolicyJSON) {
return nodeconfigs.NewNetworkSecurityPolicy(), nil
}
var policy = nodeconfigs.NewNetworkSecurityPolicy()
err = json.Unmarshal(networkSecurityPolicyJSON, policy)
if err != nil {
return nil, err
}
return policy, nil
}
// UpdateClusterHTTPPagesPolicy 修改自定义页面设置
func (this *NodeClusterDAO) UpdateClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, httpPagesPolicy *nodeconfigs.HTTPPagesPolicy) error {
if httpPagesPolicy == nil {
@@ -1449,6 +1503,11 @@ func (this *NodeClusterDAO) NotifyHTTP3Update(tx *dbs.Tx, clusterId int64) error
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTP3PolicyChanged)
}
// NotifyNetworkSecurityUpdate 通知网络安全策略更新
func (this *NodeClusterDAO) NotifyNetworkSecurityUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeNetworkSecurityPolicyChanged)
}
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)

View File

@@ -43,6 +43,8 @@ const (
NodeClusterField_HttpPages dbs.FieldName = "httpPages" // 自定义页面设置
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
NodeClusterField_AutoSystemTuning dbs.FieldName = "autoSystemTuning" // 是否自动调整系统参数
NodeClusterField_NetworkSecurity dbs.FieldName = "networkSecurity" // 网络安全策略
)
// NodeCluster 节点集群
@@ -87,6 +89,8 @@ type NodeCluster struct {
HttpPages dbs.JSON `field:"httpPages"` // 自定义页面设置
Cc dbs.JSON `field:"cc"` // CC设置
Http3 dbs.JSON `field:"http3"` // HTTP3设置
AutoSystemTuning bool `field:"autoSystemTuning"` // 是否自动调整系统参数
NetworkSecurity dbs.JSON `field:"networkSecurity"` // 网络安全策略
}
type NodeClusterOperator struct {
@@ -130,6 +134,8 @@ type NodeClusterOperator struct {
HttpPages any // 自定义页面设置
Cc any // CC设置
Http3 any // HTTP3设置
AutoSystemTuning any // 是否自动调整系统参数
NetworkSecurity any // 网络安全策略
}
func NewNodeClusterOperator() *NodeClusterOperator {

View File

@@ -37,7 +37,7 @@ func (this *NodeCluster) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
return result
}
// HasDDoSProtection 检查是否有DDOS设置
// HasDDoSProtection 检查是否有DDoS设置
func (this *NodeCluster) HasDDoSProtection() bool {
var config = this.DecodeDDoSProtection()
if config != nil {
@@ -46,6 +46,27 @@ func (this *NodeCluster) HasDDoSProtection() bool {
return false
}
// HasNetworkSecurityPolicy 检查是否有安全策略设置
func (this *NodeCluster) HasNetworkSecurityPolicy() bool {
var policy = this.DecodeNetworkSecurityPolicy()
if policy != nil {
return policy.IsOn()
}
return false
}
// DecodeNetworkSecurityPolicy 解析安全策略设置
func (this *NodeCluster) DecodeNetworkSecurityPolicy() *nodeconfigs.NetworkSecurityPolicy {
var policy = nodeconfigs.NewNetworkSecurityPolicy()
if IsNotNull(this.NetworkSecurity) {
err := json.Unmarshal(this.NetworkSecurity, policy)
if err != nil {
remotelogs.Error("NodeCluster.DecodeNetworkSecurityPolicy()", err.Error())
}
}
return policy
}
// DecodeClock 解析时钟配置
func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
var clock = nodeconfigs.DefaultClockConfig()

View File

@@ -18,7 +18,6 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -27,6 +26,7 @@ import (
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"strconv"
"strings"
"time"
@@ -1018,6 +1018,13 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
}
config.AllowedIPs = append(config.AllowedIPs, apiNodeIPs...)
// 当前的节点IP地址
nodeNodeIPs, err := SharedNodeIPAddressDAO.FindAllEnabledAddressStringsWithNode(tx, nodeId, nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
config.IPAddresses = nodeNodeIPs
// 所属集群
var primaryClusterId = int64(node.ClusterId)
var clusterIds = []int64{primaryClusterId}
@@ -1057,30 +1064,6 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
}
}
// 全局设置
// TODO 根据用户的不同读取不同的全局设置
var settingCacheKey = "SharedSysSettingDAO:" + systemconfigs.SettingCodeServerGlobalConfig
settingJSONCache, ok := cacheMap.Get(settingCacheKey)
var settingJSON []byte
if ok {
settingJSON = settingJSONCache.([]byte)
} else {
settingJSON, err = SharedSysSettingDAO.ReadSetting(tx, systemconfigs.SettingCodeServerGlobalConfig)
if err != nil {
return nil, err
}
cacheMap.Put(settingCacheKey, settingJSON)
}
if len(settingJSON) > 0 {
globalConfig := &serverconfigs.GlobalConfig{}
err = json.Unmarshal(settingJSON, globalConfig)
if err != nil {
return nil, err
}
config.GlobalConfig = globalConfig
}
var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
@@ -1100,7 +1083,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
continue
}
// 节点IP地址
// 所有节点IP地址
nodeIPAddresses, err := SharedNodeIPAddressDAO.FindAllAccessibleIPAddressesWithClusterId(tx, nodeconfigs.NodeRoleNode, clusterId, cacheMap)
if err != nil {
return nil, err
@@ -1242,6 +1225,12 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// 自动安装nftables
if clusterIndex == 0 {
config.AutoInstallNftables = nodeCluster.AutoInstallNftables
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
}
// 安全设置
if clusterIndex == 0 {
config.NetworkSecurityPolicy = nodeCluster.DecodeNetworkSecurityPolicy()
}
clusterIndex++
@@ -2128,6 +2117,12 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
Addrs: addrStrings,
SecretHash: secretHash,
})
// 排序
sort.Slice(parentNodeConfigs, func(i, j int) bool {
return parentNodeConfigs[i].Id < parentNodeConfigs[j].Id
})
result[clusterId] = parentNodeConfigs
}
}

View File

@@ -89,7 +89,9 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
op.PrivateKey = privateKey
op.Passphrase = passphrase
}
op.Su = su
if username != "root" { // only for non-root user
op.Su = su
}
op.Description = description
op.NodeId = nodeId
op.State = NodeGrantStateEnabled
@@ -117,7 +119,11 @@ func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, me
op.PrivateKey = privateKey
op.Passphrase = passphrase
}
op.Su = su
if username != "root" { // only for non-root user
op.Su = su
} else {
op.Su = false
}
op.Description = description
op.NodeId = nodeId
err := this.Save(tx, op)

View File

@@ -256,6 +256,32 @@ func (this *NodeIPAddressDAO) FindAllEnabledAddressesWithNode(tx *dbs.Tx, nodeId
return
}
// FindAllEnabledAddressStringsWithNode 查找节点的所有的IP地址地府传
func (this *NodeIPAddressDAO) FindAllEnabledAddressStringsWithNode(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []string, err error) {
if len(role) == 0 {
role = nodeconfigs.NodeRoleNode
}
ones, err := this.Query(tx).
Attr("nodeId", nodeId).
Attr("role", role).
State(NodeIPAddressStateEnabled).
Result("ip", "backupIP").
FindAll()
if err != nil {
return nil, err
}
for _, one := range ones {
var addr = one.(*NodeIPAddress)
result = append(result, addr.Ip)
if len(addr.BackupIP) > 0 {
result = append(result, addr.BackupIP)
}
}
return
}
// FindFirstNodeAccessIPAddress 查找节点的第一个可访问的IP地址
func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddress(tx *dbs.Tx, nodeId int64, mustUp bool, role nodeconfigs.NodeRole) (ip string, addrId int64, err error) {
if len(role) == 0 {

View File

@@ -8,6 +8,7 @@ import (
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"strings"
"time"
)
@@ -16,20 +17,22 @@ type NodeTaskType = string
const (
// CDN相关
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
NodeTaskTypeNetworkSecurityPolicyChanged NodeTaskType = "networkSecurityPolicyChanged" // 网络安全策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
// NS相关
@@ -265,6 +268,23 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
// UpdateNodeTaskDone 修改节点任务的完成状态
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error {
if isOk {
// 特殊任务删除
taskType, err := this.Query(tx).
Pk(taskId).
Result("type").
FindStringCol("")
if err != nil {
return err
}
if strings.HasPrefix(taskType, NodeTaskTypeIPListDeleted+"@") {
return this.Query(tx).
Pk(taskId).
DeleteQuickly()
}
}
// 其他任务标记为完成
var query = this.Query(tx).
Pk(taskId)
if !isOk {
@@ -274,8 +294,9 @@ func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool,
}
query.Set("version", version)
}
_, err := query.
Set("isDone", 1).
Set("isDone", true).
Set("isOk", isOk).
Set("error", errorMessage).
Update()

View File

@@ -54,3 +54,12 @@ func TestNodeTaskDAO_FindDoingNodeTasks(t *testing.T) {
t.Fatal(err)
}
}
func TestNodeTaskDAO_UpdateNodeTaskDone(t *testing.T) {
var tx *dbs.Tx
var dao = models.NewNodeTaskDAO()
err := dao.UpdateNodeTaskDone(tx, 1741, true, "")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,17 +1,11 @@
package models
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"strings"
"time"
)
const (
@@ -153,12 +147,13 @@ func (this *NodeThresholdDAO) FindAllEnabledAndOnClusterThresholds(tx *dbs.Tx, r
}
// FindAllEnabledAndOnNodeThresholds 查询节点专属的阈值设置
func (this *NodeThresholdDAO) FindAllEnabledAndOnNodeThresholds(tx *dbs.Tx, role string, nodeId int64, item string) (result []*NodeThreshold, err error) {
if nodeId <= 0 {
func (this *NodeThresholdDAO) FindAllEnabledAndOnNodeThresholds(tx *dbs.Tx, role string, clusterId int64, nodeId int64, item string) (result []*NodeThreshold, err error) {
if clusterId <= 0 || nodeId <= 0 {
return
}
_, err = this.Query(tx).
Attr("role", role).
Attr("clusterId", clusterId).
Attr("nodeId", nodeId).
Attr("item", item).
Attr("isOn", true).
@@ -186,87 +181,3 @@ func (this *NodeThresholdDAO) CountAllEnabledThresholds(tx *dbs.Tx, role string,
query.State(NodeThresholdStateEnabled)
return query.Count()
}
// FireNodeThreshold 触发相关阈值设置
func (this *NodeThresholdDAO) FireNodeThreshold(tx *dbs.Tx, role string, nodeId int64, item string) error {
clusterId, err := SharedNodeDAO.FindNodeClusterId(tx, nodeId)
if err != nil {
return err
}
if clusterId == 0 {
return nil
}
// 集群相关阈值
var thresholds []*NodeThreshold
{
clusterThresholds, err := this.FindAllEnabledAndOnClusterThresholds(tx, role, clusterId, item)
if err != nil {
return err
}
thresholds = append(thresholds, clusterThresholds...)
}
// 节点相关阈值
{
nodeThresholds, err := this.FindAllEnabledAndOnNodeThresholds(tx, role, nodeId, item)
if err != nil {
return err
}
thresholds = append(thresholds, nodeThresholds...)
}
if len(thresholds) > 0 {
for _, threshold := range thresholds {
if len(threshold.Param) == 0 || threshold.Duration <= 0 {
continue
}
paramValue, err := SharedNodeValueDAO.SumNodeValues(tx, role, nodeId, item, threshold.Param, threshold.SumMethod, types.Int32(threshold.Duration), threshold.DurationUnit)
if err != nil {
return err
}
originValue := nodeconfigs.UnmarshalNodeValue(threshold.Value)
thresholdValue := types.Float64(originValue)
isMatched := nodeconfigs.CompareNodeValue(threshold.Operator, paramValue, thresholdValue)
if isMatched {
// TODO 执行其他动作
// 是否已经通知过
if threshold.NotifyDuration > 0 && threshold.NotifiedAt > 0 && time.Now().Unix()-int64(threshold.NotifiedAt) < int64(threshold.NotifyDuration*60) {
continue
}
// 创建消息
nodeName, err := SharedNodeDAO.FindNodeName(tx, nodeId)
if err != nil {
return err
}
itemName := nodeconfigs.FindNodeValueItemName(threshold.Item)
paramName := nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param)
operatorName := nodeconfigs.FindNodeValueOperatorName(threshold.Operator)
subject := "节点 \"" + nodeName + "\" " + itemName + " 达到阈值"
body := "节点 \"" + nodeName + "\" " + itemName + " 达到阈值\n阈值设置" + paramName + " " + operatorName + " " + originValue + "\n当前值" + fmt.Sprintf("%.2f", paramValue) + "\n触发时间" + timeutil.Format("Y-m-d H:i:s")
if len(threshold.Message) > 0 {
body = threshold.Message
body = strings.Replace(body, "${item.name}", itemName, -1)
body = strings.Replace(body, "${value}", fmt.Sprintf("%.2f", paramValue), -1)
}
err = SharedMessageDAO.CreateNodeMessage(tx, role, clusterId, nodeId, MessageTypeThresholdSatisfied, MessageLevelWarning, subject, body, maps.Map{}.AsJSON(), true)
if err != nil {
return err
}
// 设置通知时间
_, err = this.Query(tx).
Pk(threshold.Id).
Set("notifiedAt", time.Now().Unix()).
Update()
if err != nil {
return err
}
}
}
}
return nil
}

View File

@@ -0,0 +1,12 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import "github.com/iwind/TeaGo/dbs"
// FireNodeThreshold 触发相关阈值设置
func (this *NodeThresholdDAO) FireNodeThreshold(tx *dbs.Tx, role string, nodeId int64, item string) error {
// stub
return nil
}

View File

@@ -227,6 +227,8 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
return err
}
op.Oss = ossConfigJSON
} else {
op.Oss = dbs.SQL("NULL")
}
op.Description = description
@@ -400,6 +402,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
}
// addr
var isOSS = false
if IsNotNull(origin.Addr) {
var addr = &serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(origin.Addr, addr)
@@ -407,10 +410,11 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
return nil, err
}
config.Addr = addr
isOSS = ossconfigs.IsOSSProtocol(string(addr.Protocol))
}
// oss
if IsNotNull(origin.Oss) {
if isOSS && IsNotNull(origin.Oss) {
var ossConfig = ossconfigs.NewOSSConfig()
err = json.Unmarshal(origin.Oss, ossConfig)
if err != nil {

View File

@@ -61,15 +61,28 @@ func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error {
}
// FindEnabledPlan 查找启用中的条目
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, id int64) (*Plan, error) {
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, planId int64, cacheMap *utils.CacheMap) (*Plan, error) {
var cacheKey = this.Table + ":FindEnabledPlan:" + types.String(planId)
if cacheMap != nil {
cache, _ := cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*Plan), nil
}
}
result, err := this.Query(tx).
Pk(id).
Pk(planId).
Attr("state", PlanStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Plan), err
if cacheMap != nil {
cacheMap.Put(cacheKey, result)
}
return result.(*Plan), nil
}
// FindPlanName 根据主键查找名称

View File

@@ -1,4 +1,4 @@
package models
package models_test
import (
_ "github.com/go-sql-driver/mysql"

View File

@@ -2,39 +2,71 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
PlanField_Id dbs.FieldName = "id" // ID
PlanField_IsOn dbs.FieldName = "isOn" // 是否启用
PlanField_Name dbs.FieldName = "name" // 套餐名
PlanField_ClusterId dbs.FieldName = "clusterId" // 集群ID
PlanField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
PlanField_Features dbs.FieldName = "features" // 允许的功能
PlanField_TrafficPrice dbs.FieldName = "trafficPrice" // 流量价格设定
PlanField_BandwidthPrice dbs.FieldName = "bandwidthPrice" // 带宽价格
PlanField_MonthlyPrice dbs.FieldName = "monthlyPrice" // 月付
PlanField_SeasonallyPrice dbs.FieldName = "seasonallyPrice" // 季付
PlanField_YearlyPrice dbs.FieldName = "yearlyPrice" // 年付
PlanField_PriceType dbs.FieldName = "priceType" // 价格类型
PlanField_Order dbs.FieldName = "order" // 排序
PlanField_State dbs.FieldName = "state" // 状态
PlanField_TotalServers dbs.FieldName = "totalServers" // 可以绑定的网站数量
PlanField_TotalServerNamesPerServer dbs.FieldName = "totalServerNamesPerServer" // 每个网站可以绑定的域名数量
PlanField_TotalServerNames dbs.FieldName = "totalServerNames" // 总域名数量
PlanField_MonthlyRequests dbs.FieldName = "monthlyRequests" // 每月访问量额度
PlanField_DailyRequests dbs.FieldName = "dailyRequests" // 每日访问量额度
)
// Plan 用户套餐
type Plan struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名
ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
YearlyPrice float64 `field:"yearlyPrice"` // 年付
PriceType string `field:"priceType"` // 价格类型
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名
ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
YearlyPrice float64 `field:"yearlyPrice"` // 年付
PriceType string `field:"priceType"` // 价格类型
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
TotalServers uint32 `field:"totalServers"` // 可以绑定的网站数量
TotalServerNamesPerServer uint32 `field:"totalServerNamesPerServer"` // 每个网站可以绑定的域名数量
TotalServerNames uint32 `field:"totalServerNames"` // 总域名数量
MonthlyRequests uint64 `field:"monthlyRequests"` // 每月访问量额度
DailyRequests uint64 `field:"dailyRequests"` // 每日访问量额度
}
type PlanOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
Name interface{} // 套餐名
ClusterId interface{} // 集群ID
TrafficLimit interface{} // 流量限制
Features interface{} // 允许的功能
TrafficPrice interface{} // 流量价格设定
BandwidthPrice interface{} // 带宽价格
MonthlyPrice interface{} // 月付
SeasonallyPrice interface{} // 季付
YearlyPrice interface{} // 年付
PriceType interface{} // 价格类型
Order interface{} // 排序
State interface{} // 状态
Id any // ID
IsOn any // 是否启用
Name any // 套餐名
ClusterId any // 集群ID
TrafficLimit any // 流量限制
Features any // 允许的功能
TrafficPrice any // 流量价格设定
BandwidthPrice any // 带宽价格
MonthlyPrice any // 月付
SeasonallyPrice any // 季付
YearlyPrice any // 年付
PriceType any // 价格类型
Order any // 排序
State any // 状态
TotalServers any // 可以绑定的网站数量
TotalServerNamesPerServer any // 每个网站可以绑定的域名数量
TotalServerNames any // 总域名数量
MonthlyRequests any // 每月访问量额度
DailyRequests any // 每日访问量额度
}
func NewPlanOperator() *PlanOperator {

View File

@@ -99,7 +99,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, nil
}
var config = &serverconfigs.ReverseProxyConfig{}
var config = serverconfigs.NewReverseProxyConfig()
config.Id = int64(reverseProxy.Id)
config.IsOn = reverseProxy.IsOn
config.RequestHostType = types.Int8(reverseProxy.RequestHostType)
@@ -109,6 +109,8 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
config.StripPrefix = reverseProxy.StripPrefix
config.AutoFlush = reverseProxy.AutoFlush == 1
config.FollowRedirects = reverseProxy.FollowRedirects == 1
config.Retry50X = reverseProxy.Retry50X
config.Retry40X = reverseProxy.Retry40X
var schedulingConfig = &serverconfigs.SchedulingConfig{}
if IsNotNull(reverseProxy.Scheduling) {
@@ -218,6 +220,8 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
op.AdminId = adminId
op.UserId = userId
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
op.Retry50X = false
op.Retry40X = false
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
@@ -425,7 +429,9 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
maxConns int32,
maxIdleConns int32,
proxyProtocolJSON []byte,
followRedirects bool) error {
followRedirects bool,
retry50X bool,
retry40X bool) error {
if reverseProxyId <= 0 {
return errors.New("invalid reverseProxyId")
}
@@ -490,6 +496,9 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
op.ProxyProtocol = proxyProtocolJSON
}
op.Retry50X = retry50X
op.Retry40X = retry40X
err = this.Save(tx, op)
if err != nil {
return err

View File

@@ -2,6 +2,35 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
ReverseProxyField_Id dbs.FieldName = "id" // ID
ReverseProxyField_AdminId dbs.FieldName = "adminId" // 管理员ID
ReverseProxyField_UserId dbs.FieldName = "userId" // 用户ID
ReverseProxyField_TemplateId dbs.FieldName = "templateId" // 模版ID
ReverseProxyField_IsOn dbs.FieldName = "isOn" // 是否启用
ReverseProxyField_Scheduling dbs.FieldName = "scheduling" // 调度算法
ReverseProxyField_PrimaryOrigins dbs.FieldName = "primaryOrigins" // 主要源站
ReverseProxyField_BackupOrigins dbs.FieldName = "backupOrigins" // 备用源站
ReverseProxyField_StripPrefix dbs.FieldName = "stripPrefix" // 去除URL前缀
ReverseProxyField_RequestHostType dbs.FieldName = "requestHostType" // 请求Host类型
ReverseProxyField_RequestHost dbs.FieldName = "requestHost" // 请求Host
ReverseProxyField_RequestHostExcludingPort dbs.FieldName = "requestHostExcludingPort" // 移除请求Host中的域名
ReverseProxyField_RequestURI dbs.FieldName = "requestURI" // 请求URI
ReverseProxyField_AutoFlush dbs.FieldName = "autoFlush" // 是否自动刷新缓冲区
ReverseProxyField_AddHeaders dbs.FieldName = "addHeaders" // 自动添加的Header列表
ReverseProxyField_State dbs.FieldName = "state" // 状态
ReverseProxyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
ReverseProxyField_ConnTimeout dbs.FieldName = "connTimeout" // 连接超时时间
ReverseProxyField_ReadTimeout dbs.FieldName = "readTimeout" // 读取超时时间
ReverseProxyField_IdleTimeout dbs.FieldName = "idleTimeout" // 空闲超时时间
ReverseProxyField_MaxConns dbs.FieldName = "maxConns" // 最大并发连接数
ReverseProxyField_MaxIdleConns dbs.FieldName = "maxIdleConns" // 最大空闲连接数
ReverseProxyField_ProxyProtocol dbs.FieldName = "proxyProtocol" // Proxy Protocol配置
ReverseProxyField_FollowRedirects dbs.FieldName = "followRedirects" // 回源跟随
ReverseProxyField_Retry50X dbs.FieldName = "retry50X" // 启用50X重试
ReverseProxyField_Retry40X dbs.FieldName = "retry40X" // 启用40X重试
)
// ReverseProxy 反向代理配置
type ReverseProxy struct {
Id uint32 `field:"id"` // ID
@@ -28,33 +57,37 @@ type ReverseProxy struct {
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
Retry50X bool `field:"retry50X"` // 启用50X重试
Retry40X bool `field:"retry40X"` // 启用40X重试
}
type ReverseProxyOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
TemplateId interface{} // 模版ID
IsOn interface{} // 是否启用
Scheduling interface{} // 调度算法
PrimaryOrigins interface{} // 主要源站
BackupOrigins interface{} // 备用源站
StripPrefix interface{} // 去除URL前缀
RequestHostType interface{} // 请求Host类型
RequestHost interface{} // 请求Host
RequestHostExcludingPort interface{} // 移除请求Host中的域名
RequestURI interface{} // 请求URI
AutoFlush interface{} // 是否自动刷新缓冲区
AddHeaders interface{} // 自动添加的Header列表
State interface{} // 状态
CreatedAt interface{} // 创建时间
ConnTimeout interface{} // 连接超时时间
ReadTimeout interface{} // 读取超时时间
IdleTimeout interface{} // 空闲超时时间
MaxConns interface{} // 最大并发连接数
MaxIdleConns interface{} // 最大空闲连接数
ProxyProtocol interface{} // Proxy Protocol配置
FollowRedirects interface{} // 回源跟随
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
TemplateId any // 模版ID
IsOn any // 是否启用
Scheduling any // 调度算法
PrimaryOrigins any // 主要源站
BackupOrigins any // 备用源站
StripPrefix any // 去除URL前缀
RequestHostType any // 请求Host类型
RequestHost any // 请求Host
RequestHostExcludingPort any // 移除请求Host中的域名
RequestURI any // 请求URI
AutoFlush any // 是否自动刷新缓冲区
AddHeaders any // 自动添加的Header列表
State any // 状态
CreatedAt any // 创建时间
ConnTimeout any // 连接超时时间
ReadTimeout any // 读取超时时间
IdleTimeout any // 空闲超时时间
MaxConns any // 最大并发连接数
MaxIdleConns any // 最大空闲连接数
ProxyProtocol any // Proxy Protocol配置
FollowRedirects any // 回源跟随
Retry50X any // 启用50X重试
Retry40X any // 启用40X重试
}
func NewReverseProxyOperator() *ReverseProxyOperator {

View File

@@ -25,7 +25,7 @@ import (
type ServerBandwidthStatDAO dbs.DAO
const (
ServerBandwidthStatTablePartials = 20 // 分表数量
ServerBandwidthStatTablePartitions = 20 // 分表数量
)
func init() {
@@ -63,15 +63,15 @@ func init() {
}
// UpdateServerBandwidth 写入数据
// 暂时不使用region区分
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, day string, timeAt string, bytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
// 现在不需要把 userPlanId 加入到数据表unique key中因为只会影响5分钟统计影响非常有限
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, userPlanId int64, day string, timeAt string, bandwidthBytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
if serverId <= 0 {
return errors.New("invalid server id '" + types.String(serverId) + "'")
}
return this.Query(tx).
Table(this.partialTable(serverId)).
Param("bytes", bytes).
Param("bytes", bandwidthBytes).
Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
@@ -84,7 +84,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"bytes": bandwidthBytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
@@ -92,6 +92,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
"userPlanId": userPlanId,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
@@ -379,14 +380,18 @@ func (this *ServerBandwidthStatDAO) FindAllServerStatsWithMonth(tx *dbs.Tx, serv
}
// FindMonthlyPercentile 获取某月内百分位
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool) (result int64, err error) {
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool, noPlan bool, minSamples int) (result int64, err error) {
if percentile <= 0 {
percentile = 95
}
// 如果是100%以上,则快速返回
if percentile >= 100 {
result, err = this.Query(tx).
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
result, err = query.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Result(this.bytesField(useAvg)).
@@ -398,7 +403,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
}
// 总数量
total, err := this.Query(tx).
var totalQuery = this.Query(tx)
if noPlan {
totalQuery.Attr("userPlanId", 0)
}
total, err := totalQuery.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
@@ -406,7 +415,7 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
if err != nil {
return 0, err
}
if total == 0 {
if total == 0 || total < int64(minSamples) {
return 0, nil
}
@@ -417,7 +426,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
}
// 查询 nth 位置
result, err = this.Query(tx).
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
result, err = query.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Result(this.bytesField(useAvg)).
@@ -745,6 +758,74 @@ func (this *ServerBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, reg
return
}
// SumMonthlyBytes 统计某个网站单月总流量
func (this *ServerBandwidthStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, month string, noPlan bool) (int64, error) {
if !regexputils.YYYYMM.MatchString(month) {
return 0, errors.New("invalid month '" + month + "'")
}
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, serverId, month)
if err != nil {
return 0, err
}
if !hasFullData {
return SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
}
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
return query.
Table(this.partialTable(serverId)).
Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("totalBytes", 0)
}
// SumServerMonthlyWithRegion 根据服务计算某月合计
// month 格式为YYYYMM
func (this *ServerBandwidthStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId int64, regionId int64, month string, noPlan bool) (int64, error) {
var query = this.Query(tx)
query.Table(this.partialTable(serverId))
if regionId > 0 {
query.Attr("regionId", regionId)
}
if noPlan {
query.Attr("userPlanId", 0)
}
return query.Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("totalBytes", 0)
}
// FindDistinctServerIdsWithoutPlanAtPartition 查找没有绑定套餐的有流量网站
func (this *ServerBandwidthStatDAO) FindDistinctServerIdsWithoutPlanAtPartition(tx *dbs.Tx, partitionIndex int, month string) (serverIds []int64, err error) {
ones, err := this.Query(tx).
Table(this.partialTable(int64(partitionIndex))).
Between("day", month+"01", month+"31").
Attr("userPlanId", 0). // 没有绑定套餐
Result("DISTINCT serverId").
FindAll()
if err != nil {
return nil, err
}
for _, one := range ones {
var serverId = int64(one.(*ServerBandwidthStat).ServerId)
if serverId <= 0 {
continue
}
serverIds = append(serverIds, serverId)
}
return
}
// CountPartitions 查看分区数量
func (this *ServerBandwidthStatDAO) CountPartitions() int {
return ServerBandwidthStatTablePartitions
}
// CleanDays 清理过期数据
func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
@@ -777,9 +858,9 @@ func (this *ServerBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
var wg = sync.WaitGroup{}
wg.Add(ServerBandwidthStatTablePartials)
wg.Add(ServerBandwidthStatTablePartitions)
var resultErr error
for i := 0; i < ServerBandwidthStatTablePartials; i++ {
for i := 0; i < ServerBandwidthStatTablePartitions; i++ {
var table = this.partialTable(int64(i))
go func(table string) {
defer wg.Done()
@@ -796,7 +877,7 @@ func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.M
// 获取分区表
func (this *ServerBandwidthStatDAO) partialTable(serverId int64) string {
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartials))
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartitions))
}
// 获取字节字段

View File

@@ -16,7 +16,7 @@ import (
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
if err != nil {
t.Fatal(err)
}
@@ -33,7 +33,7 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200)))
var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
if err != nil {
t.Fatal(err)
}
@@ -44,8 +44,10 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
func TestServerBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false, false, 0))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 0))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 100))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, true, 0))
}
func TestServerBandwidthStatDAO_FindAllServerStatsWithMonth(t *testing.T) {
@@ -114,3 +116,32 @@ func TestServerBandwidthStatDAO_FindBandwidthStatsBetweenDays(t *testing.T) {
t.Log(stat.Day, stat.TimeAt, "bytes:", stat.Bytes, "bits:", stat.Bits)
}
}
func TestServerBandwidthStatDAO_SumServerMonthlyWithRegion(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
{
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), false)
if err != nil {
t.Fatal(err)
}
t.Log("with plan:", totalBytes)
}
{
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), true)
if err != nil {
t.Fatal(err)
}
t.Log("without plan:", totalBytes)
}
}
func TestServerBandwidthStatDAO_SumMonthlyBytes(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
totalBytes, err := dao.SumMonthlyBytes(tx, 23, timeutil.Format("Ym"), false)
if err != nil {
t.Fatal(err)
}
t.Log("total bytes:", totalBytes)
}

View File

@@ -1,11 +1,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
ServerBandwidthStatField_Id dbs.FieldName = "id" // ID
ServerBandwidthStatField_UserId dbs.FieldName = "userId" // 用户ID
ServerBandwidthStatField_ServerId dbs.FieldName = "serverId" // 服务ID
ServerBandwidthStatField_RegionId dbs.FieldName = "regionId" // 区域ID
ServerBandwidthStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
ServerBandwidthStatField_Day dbs.FieldName = "day" // 日期YYYYMMDD
ServerBandwidthStatField_TimeAt dbs.FieldName = "timeAt" // 时间点HHMM
ServerBandwidthStatField_Bytes dbs.FieldName = "bytes" // 带宽字节
ServerBandwidthStatField_AvgBytes dbs.FieldName = "avgBytes" // 平均流量
ServerBandwidthStatField_CachedBytes dbs.FieldName = "cachedBytes" // 缓存的流量
ServerBandwidthStatField_AttackBytes dbs.FieldName = "attackBytes" // 攻击流量
ServerBandwidthStatField_CountRequests dbs.FieldName = "countRequests" // 请求数
ServerBandwidthStatField_CountCachedRequests dbs.FieldName = "countCachedRequests" // 缓存的请求数
ServerBandwidthStatField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 攻击请求数
ServerBandwidthStatField_TotalBytes dbs.FieldName = "totalBytes" // 总流量
)
// ServerBandwidthStat 服务峰值带宽统计
type ServerBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
RegionId uint32 `field:"regionId"` // 区域ID
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节
@@ -23,6 +44,7 @@ type ServerBandwidthStatOperator struct {
UserId any // 用户ID
ServerId any // 服务ID
RegionId any // 区域ID
UserPlanId any // 用户套餐ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHMM
Bytes any // 带宽字节

View File

@@ -119,7 +119,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
// 更新流量限制状态
if stat.CheckTrafficLimiting {
trafficLimitConfig, err := SharedServerDAO.CalculateServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
trafficLimitConfig, err := SharedServerDAO.FindServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
if err != nil {
return err
}
@@ -129,7 +129,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
return err
}
err = SharedServerDAO.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
err = SharedServerDAO.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
if err != nil {
return err
}
@@ -140,6 +140,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
return nil
}
// SumCurrentDailyStat 查找当前时刻的数据统计
func (this *ServerDailyStatDAO) SumCurrentDailyStat(tx *dbs.Tx, serverId int64) (*ServerDailyStat, error) {
var day = timeutil.Format("Ymd")
@@ -164,7 +165,7 @@ func (this *ServerDailyStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId
if regionId > 0 {
query.Attr("regionId", regionId)
}
return query.Between("day", month+"01", month+"32").
return query.Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("bytes", 0)
}
@@ -178,7 +179,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyWithoutPlan(tx *dbs.Tx, userId int
}
return query.
Attr("planId", 0).
Between("day", month+"01", month+"32").
Between("day", month+"01", month+"31").
Attr("userId", userId).
SumInt64("bytes", 0)
}
@@ -190,7 +191,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, reg
if regionId > 0 {
query.Attr("regionId", regionId)
}
max, err := query.Between("day", month+"01", month+"32").
max, err := query.Between("day", month+"01", month+"31").
Attr("userId", userId).
Max("bytes", 0)
if err != nil {
@@ -644,7 +645,7 @@ func (this *ServerDailyStatDAO) FindStatsBetweenDays(tx *dbs.Tx, userId int64, s
// month YYYYMM
func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month string) (result []*ServerDailyStat, err error) {
_, err = this.Query(tx).
Between("day", month+"01", month+"32").
Between("day", month+"01", month+"31").
Gt("planId", 0).
Slice(&result).
FindAll()

View File

@@ -3,11 +3,13 @@ package models
import (
"encoding/json"
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -782,7 +784,7 @@ func (this *ServerDAO) CountAllEnabledServers(tx *dbs.Tx) (int64, error) {
// 参数:
//
// groupId 分组ID如果为-1则搜索没有分组的服务
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string) (int64, error) {
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string, userPlanId int64) (int64, error) {
query := this.Query(tx).
State(ServerStateEnabled)
if groupId > 0 {
@@ -829,6 +831,10 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
query.Where("(" + strings.Join(protocolConds, " OR ") + ")")
}
if userPlanId > 0 {
query.Attr("userPlanId", userPlanId)
}
return query.Count()
}
@@ -1316,12 +1322,13 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
}
// 套餐是否依然有效
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
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),
@@ -1341,16 +1348,14 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
}
}
if config.TrafficLimit != nil && config.TrafficLimit.IsOn && !config.TrafficLimit.IsEmpty() {
if len(server.TrafficLimitStatus) > 0 {
var status = &serverconfigs.TrafficLimitStatus{}
err := json.Unmarshal(server.TrafficLimitStatus, status)
if err != nil {
return nil, err
}
if status.IsValid() {
config.TrafficLimitStatus = status
}
if len(server.TrafficLimitStatus) > 0 {
var status = &serverconfigs.TrafficLimitStatus{}
err := json.Unmarshal(server.TrafficLimitStatus, status)
if err != nil {
return nil, err
}
if status.IsValid() {
config.TrafficLimitStatus = status
}
}
@@ -1794,6 +1799,7 @@ func (this *ServerDAO) FindServerUserId(tx *dbs.Tx, serverId int64) (userId int6
}
// FindServerUserPlanId 查找服务的套餐ID
// TODO 需要缓存
func (this *ServerDAO) FindServerUserPlanId(tx *dbs.Tx, serverId int64) (userPlanId int64, err error) {
return this.Query(tx).
Pk(serverId).
@@ -2039,11 +2045,12 @@ func (this *ServerDAO) GenDNSName(tx *dbs.Tx) (string, error) {
// FindLatestServers 查询最近访问的服务
func (this *ServerDAO) FindLatestServers(tx *dbs.Tx, size int64) (result []*Server, err error) {
itemTable := SharedLatestItemDAO.Table
itemType := LatestItemTypeServer
var itemTable = SharedLatestItemDAO.Table
var itemType = LatestItemTypeServer
_, err = this.Query(tx).
Result(this.Table+".id", this.Table+".name").
Join(SharedLatestItemDAO, dbs.QueryJoinRight, this.Table+".id="+itemTable+".itemId AND "+itemTable+".itemType='"+itemType+"'").
Where(itemTable + ".updatedAt<=UNIX_TIMESTAMP()"). // VERY IMPORTANT
Asc("CEIL((UNIX_TIMESTAMP() - " + itemTable + ".updatedAt) / (7 * 86400))"). // 优先一个星期以内的
Desc(itemTable + ".count").
State(NodeClusterStateEnabled).
@@ -2306,94 +2313,17 @@ func (this *ServerDAO) FindServerTrafficLimitConfig(tx *dbs.Tx, serverId int64,
return nil, err
}
var limit = &serverconfigs.TrafficLimitConfig{}
if serverOne == nil {
return limit, nil
}
var trafficLimit = serverOne.(*Server).TrafficLimit
if len(trafficLimit) > 0 {
err = json.Unmarshal([]byte(trafficLimit), limit)
if err != nil {
return nil, err
}
}
if cacheMap != nil {
cacheMap.Put(cacheKey, limit)
}
return limit, nil
}
// CalculateServerTrafficLimitConfig 计算服务的流量限制
// TODO 优化性能
func (this *ServerDAO) CalculateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64, cacheMap *utils.CacheMap) (*serverconfigs.TrafficLimitConfig, error) {
if cacheMap == nil {
cacheMap = utils.NewCacheMap()
}
var cacheKey = this.Table + ":FindServerTrafficLimitConfig:" + types.String(serverId)
result, ok := cacheMap.Get(cacheKey)
if ok {
return result.(*serverconfigs.TrafficLimitConfig), nil
}
serverOne, err := this.Query(tx).
Pk(serverId).
Result("trafficLimit", "userPlanId").
Find()
if err != nil {
return nil, err
}
var limitConfig = &serverconfigs.TrafficLimitConfig{}
if serverOne == nil {
return limitConfig, nil
}
var trafficLimit = serverOne.(*Server).TrafficLimit
var userPlanId = int64(serverOne.(*Server).UserPlanId)
var trafficLimitJSON = serverOne.(*Server).TrafficLimit
if len(trafficLimit) == 0 {
if userPlanId > 0 {
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
if err != nil {
return nil, err
}
if userPlan != nil {
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
if err != nil {
return nil, err
}
if planLimit != nil {
return planLimit, nil
}
}
}
return limitConfig, nil
}
err = json.Unmarshal(trafficLimit, limitConfig)
if err != nil {
return nil, err
}
if !limitConfig.IsOn {
if userPlanId > 0 {
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
if err != nil {
return nil, err
}
if userPlan != nil {
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
if err != nil {
return nil, err
}
if planLimit != nil {
return planLimit, nil
}
}
if len(trafficLimitJSON) > 0 {
err = json.Unmarshal(trafficLimitJSON, limitConfig)
if err != nil {
return nil, err
}
}
@@ -2423,11 +2353,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64
}
// 更新状态
return this.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
return this.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
}
// UpdateServerTrafficLimitStatus 修改服务的流量限制状态
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
// RenewServerTrafficLimitStatus 根据限流配置更新网站的流量限制状态
func (this *ServerDAO) RenewServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
if !trafficLimitConfig.IsOn {
if isUpdatingConfig {
return this.NotifyUpdate(tx, serverId)
@@ -2464,9 +2394,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
var untilDay = ""
// daily
var dateType = ""
if trafficLimitConfig.DailyBytes() > 0 {
if server.TrafficDay == timeutil.Format("Ymd") && server.TotalDailyTraffic >= float64(trafficLimitConfig.DailyBytes())/(1<<30) {
untilDay = timeutil.Format("Ymd")
dateType = "day"
}
}
@@ -2474,6 +2406,7 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
if server.TrafficMonth == timeutil.Format("Ym") && trafficLimitConfig.MonthlyBytes() > 0 {
if server.TotalMonthlyTraffic >= float64(trafficLimitConfig.MonthlyBytes())/(1<<30) {
untilDay = timeutil.Format("Ym32")
dateType = "month"
}
}
@@ -2481,12 +2414,17 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
if trafficLimitConfig.TotalBytes() > 0 {
if server.TotalTraffic >= float64(trafficLimitConfig.TotalBytes())/(1<<30) {
untilDay = "30000101"
dateType = "total"
}
}
var isChanged = oldStatus.UntilDay != untilDay
if isChanged {
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{UntilDay: untilDay})
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{
UntilDay: untilDay,
DateType: dateType,
TargetType: serverconfigs.TrafficLimitTargetTraffic,
})
if err != nil {
return err
}
@@ -2507,6 +2445,91 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
return nil
}
// UpdateServerTrafficLimitStatus 修改网站的流量限制状态
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, serverId int64, day string, planId int64, dateType string, targetType string) error {
if !regexputils.YYYYMMDD.MatchString(day) {
return errors.New("invalid 'day' format")
}
if serverId <= 0 {
return nil
}
// lookup old status
statusJSON, err := this.Query(tx).
Pk(serverId).
Result(ServerField_TrafficLimitStatus).
FindJSONCol()
if err != nil {
return err
}
if IsNotNull(statusJSON) {
var oldStatus = &serverconfigs.TrafficLimitStatus{}
err = json.Unmarshal(statusJSON, oldStatus)
if err != nil {
return err
}
if len(oldStatus.UntilDay) > 0 && oldStatus.UntilDay >= day /** 如果已经限制,且比当前日期长,则无需重复 **/ {
// no need to change
return nil
}
}
var status = &serverconfigs.TrafficLimitStatus{
UntilDay: day,
PlanId: planId,
DateType: dateType,
TargetType: targetType,
}
statusJSON, err = json.Marshal(status)
if err != nil {
return err
}
err = this.Query(tx).
Pk(serverId).
Set(ServerField_TrafficLimitStatus, statusJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, serverId)
}
// UpdateServersTrafficLimitStatusWithUserPlanId 修改某个套餐下的网站的流量限制状态
func (this *ServerDAO) UpdateServersTrafficLimitStatusWithUserPlanId(tx *dbs.Tx, userPlanId int64, day string, planId int64, dateType string, targetType serverconfigs.TrafficLimitTarget) error {
if userPlanId <= 0 {
return nil
}
servers, err := this.Query(tx).
State(ServerStateEnabled).
Attr("userPlanId", userPlanId).
ResultPk().
FindAll()
if err != nil {
return err
}
for _, server := range servers {
var serverId = int64(server.(*Server).Id)
err = this.UpdateServerTrafficLimitStatus(tx, serverId, day, planId, dateType, targetType)
if err != nil {
return err
}
}
return nil
}
// ResetServersTrafficLimitStatusWithPlanId 重置网站限流状态
func (this *ServerDAO) ResetServersTrafficLimitStatusWithPlanId(tx *dbs.Tx, planId int64) error {
return this.Query(tx).
Where("JSON_EXTRACT(trafficLimitStatus, '$.planId')=:planId").
Param("planId", planId).
Set("trafficLimitStatus", dbs.SQL("NULL")).
UpdateQuickly()
}
// IncreaseServerTotalTraffic 增加服务的总流量
func (this *ServerDAO) IncreaseServerTotalTraffic(tx *dbs.Tx, serverId int64, bytes int64) error {
if serverId <= 0 {
@@ -2548,17 +2571,16 @@ func (this *ServerDAO) FindEnabledServerIdWithUserPlanId(tx *dbs.Tx, userPlanId
FindInt64Col(0)
}
// FindEnabledServerWithUserPlanId 查找使用某个套餐的服务
func (this *ServerDAO) FindEnabledServerWithUserPlanId(tx *dbs.Tx, userPlanId int64) (*Server, error) {
one, err := this.Query(tx).
// FindEnabledServersWithUserPlanId 查找使用某个套餐的网站
func (this *ServerDAO) FindEnabledServersWithUserPlanId(tx *dbs.Tx, userPlanId int64) (result []*Server, err error) {
_, err = this.Query(tx).
State(ServerStateEnabled).
Attr("userPlanId", userPlanId).
Result("id", "name", "serverNames", "type").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*Server), nil
AscPk().
Slice(&result).
FindAll()
return
}
// UpdateServersClusterIdWithPlanId 修改套餐所在集群
@@ -2643,7 +2665,7 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
return errors.New("can not find user plan with id '" + types.String(userPlanId) + "'")
}
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return err
}
@@ -2881,6 +2903,89 @@ func (this *ServerDAO) FindEnabledServersWithIds(tx *dbs.Tx, serverIds []int64)
return
}
// CountAllServerNamesWithUserId 计算某个用户下的所有域名数
func (this *ServerDAO) CountAllServerNamesWithUserId(tx *dbs.Tx, userId int64, userPlanId int64) (int64, error) {
if userId <= 0 {
return 0, nil
}
var query = this.Query(tx).
Attr("userId", userId).
State(ServerStateEnabled).
Where("JSON_TYPE(plainServerNames)='ARRAY'")
if userPlanId > 0 {
query.Attr("userPlanId", userPlanId)
}
return query.
SumInt64("JSON_LENGTH(plainServerNames)", 0)
}
// CountServerNames 计算某个网站下的所有域名数
func (this *ServerDAO) CountServerNames(tx *dbs.Tx, serverId int64) (int64, error) {
if serverId <= 0 {
return 0, nil
}
return this.Query(tx).
Result("JSON_LENGTH(plainServerNames)").
Pk(serverId).
State(ServerStateEnabled).
Where("JSON_TYPE(plainServerNames)='ARRAY'").
FindInt64Col(0)
}
// CheckServerPlanQuota 检查网站套餐限制
func (this *ServerDAO) CheckServerPlanQuota(tx *dbs.Tx, serverId int64, countServerNames int) error {
if serverId <= 0 {
return errors.New("invalid 'serverId'")
}
if countServerNames <= 0 {
return nil
}
userPlanId, err := this.FindServerUserPlanId(tx, serverId)
if err != nil {
return err
}
if userPlanId <= 0 {
return nil
}
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, nil)
if err != nil {
return err
}
if userPlan == nil {
return fmt.Errorf("invalid user plan with id %q", types.String(userPlanId))
}
if userPlan.IsExpired() {
return errors.New("the user plan has been expired")
}
if userPlan.UserId == 0 {
return nil
}
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return err
}
if plan == nil {
return fmt.Errorf("invalid plan with id %q", types.String(userPlan.PlanId))
}
if plan.TotalServerNames > 0 {
totalServerNames, err := this.CountAllServerNamesWithUserId(tx, int64(userPlan.UserId), userPlanId)
if err != nil {
return err
}
if totalServerNames+int64(countServerNames) > int64(plan.TotalServerNames) {
return errors.New("server names over plan quota")
}
}
if plan.TotalServerNamesPerServer > 0 {
if countServerNames > types.Int(plan.TotalServerNamesPerServer) {
return errors.New("server names per server over plan quota")
}
}
return nil
}
// NotifyUpdate 同步服务所在的集群
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {

View File

@@ -10,26 +10,26 @@ import (
)
// CopyServerConfigToServers 拷贝服务配置到一组服务
func (this *ServerDAO) CopyServerConfigToServers(tx *dbs.Tx, fromServerId int64, toServerIds []int64, configCode serverconfigs.ConfigCode) error {
func (this *ServerDAO) CopyServerConfigToServers(tx *dbs.Tx, fromServerId int64, toServerIds []int64, configCode serverconfigs.ConfigCode, wafCopyRegions bool) error {
return errors.New("not implemented")
}
// CopyServerConfigToGroups 拷贝服务配置到分组
func (this *ServerDAO) CopyServerConfigToGroups(tx *dbs.Tx, fromServerId int64, groupIds []int64, configCode string) error {
func (this *ServerDAO) CopyServerConfigToGroups(tx *dbs.Tx, fromServerId int64, groupIds []int64, configCode string, wafCopyRegions bool) error {
return errors.New("not implemented")
}
// CopyServerConfigToCluster 拷贝服务配置到集群
func (this *ServerDAO) CopyServerConfigToCluster(tx *dbs.Tx, fromServerId int64, clusterId int64, configCode string) error {
func (this *ServerDAO) CopyServerConfigToCluster(tx *dbs.Tx, fromServerId int64, clusterId int64, configCode string, wafCopyRegions bool) error {
return errors.New("not implemented")
}
// CopyServerConfigToUser 拷贝服务配置到用户
func (this *ServerDAO) CopyServerConfigToUser(tx *dbs.Tx, fromServerId int64, userId int64, configCode string) error {
func (this *ServerDAO) CopyServerConfigToUser(tx *dbs.Tx, fromServerId int64, userId int64, configCode string, wafCopyRegions bool) error {
return errors.New("not implemented")
}
// CopyServerUAMConfigs 复制UAM设置
func (this *ServerDAO) CopyServerUAMConfigs(tx *dbs.Tx, fromServerId int64, toServerIds []int64) error {
func (this *ServerDAO) CopyServerUAMConfigs(tx *dbs.Tx, fromServerId int64, toServerIds []int64, wafCopyRegions bool) error {
return errors.New("not implemented")
}

View File

@@ -242,7 +242,7 @@ func TestServerDAO_FindEnabledServerWithDomain(t *testing.T) {
}
}
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
func TestServerDAO_RenewServerTrafficLimitStatus(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
@@ -250,7 +250,7 @@ func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
err := models.NewServerDAO().UpdateServerTrafficLimitStatus(tx, &serverconfigs.TrafficLimitConfig{
err := models.NewServerDAO().RenewServerTrafficLimitStatus(tx, &serverconfigs.TrafficLimitConfig{
IsOn: true,
DailySize: &shared.SizeCapacity{Count: 1, Unit: "mb"},
MonthlySize: &shared.SizeCapacity{Count: 10, Unit: "mb"},
@@ -263,40 +263,15 @@ func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
t.Log("ok")
}
func TestServerDAO_CalculateServerTrafficLimitConfig(t *testing.T) {
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
dbs.NotifyReady()
var dao = models.NewServerDAO()
var tx *dbs.Tx
before := time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
var cacheMap = utils.NewCacheMap()
config, err := models.SharedServerDAO.CalculateServerTrafficLimitConfig(tx, 23, cacheMap)
err := dao.UpdateServerTrafficLimitStatus(tx, 23, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 20)), 14, "day", "traffic")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(config, t)
}
func TestServerDAO_CalculateServerTrafficLimitConfig_Cache(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
before := time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
var cacheMap = utils.NewCacheMap()
for i := 0; i < 10; i++ {
config, err := models.SharedServerDAO.CalculateServerTrafficLimitConfig(tx, 23, cacheMap)
if err != nil {
t.Fatal(err)
}
_ = config
}
}
func TestServerDAO_FindBytes(t *testing.T) {

View File

@@ -285,7 +285,7 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
}
// CountCerts 计算符合条件的证书数量
func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string) (int64, error) {
func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string, userOnly bool) (int64, error) {
var query = this.Query(tx).
State(SSLCertStateEnabled)
if isCA {
@@ -308,8 +308,12 @@ func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isEx
if userId > 0 {
query.Attr("userId", userId)
} else {
// 只查询管理员上传的
query.Attr("userId", 0)
if userOnly {
query.Gt("userId", 0)
} else {
// 只查询管理员上传的
query.Attr("userId", 0)
}
}
// 域名
@@ -322,7 +326,7 @@ func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isEx
}
// ListCertIds 列出符合条件的证书
func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string, offset int64, size int64) (certIds []int64, err error) {
func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string, userOnly bool, offset int64, size int64) (certIds []int64, err error) {
var query = this.Query(tx).
State(SSLCertStateEnabled)
if isCA {
@@ -345,8 +349,12 @@ func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isE
if userId > 0 {
query.Attr("userId", userId)
} else {
// 只查询管理员上传的
query.Attr("userId", 0)
if userOnly {
query.Gt("userId", 0)
} else {
// 只查询管理员上传的
query.Attr("userId", 0)
}
}
// 域名
@@ -434,6 +442,14 @@ func (this *SSLCertDAO) CheckUserCert(tx *dbs.Tx, certId int64, userId int64) er
return nil
}
// FindCertUserId 查找证书所属用户ID
func (this *SSLCertDAO) FindCertUserId(tx *dbs.Tx, certId int64) (userId int64, err error) {
return this.Query(tx).
Pk(certId).
Result("userId").
FindInt64Col(0)
}
// UpdateCertUser 修改证书所属用户
func (this *SSLCertDAO) UpdateCertUser(tx *dbs.Tx, certId int64, userId int64) error {
if certId <= 0 || userId <= 0 {

View File

@@ -83,7 +83,7 @@ func (this *ServerDomainHourlyStatDAO) IncreaseHourlyStat(tx *dbs.Tx, clusterId
if len(hour) != 10 {
return errors.New("invalid hour '" + hour + "'")
}
if len(domain) == 0 {
if len(domain) == 0 || len(domain) > 64 {
return nil
}
err := this.Query(tx).

View File

@@ -7,7 +7,6 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/zero"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -126,23 +125,6 @@ func (this *SysSettingDAO) CompareInt64Setting(tx *dbs.Tx, code string, anotherV
return 0, nil
}
// ReadGlobalConfig 读取全局配置
func (this *SysSettingDAO) ReadGlobalConfig(tx *dbs.Tx) (*serverconfigs.GlobalConfig, error) {
globalConfigData, err := this.ReadSetting(tx, systemconfigs.SettingCodeServerGlobalConfig)
if err != nil {
return nil, err
}
if len(globalConfigData) == 0 {
return &serverconfigs.GlobalConfig{}, nil
}
config := &serverconfigs.GlobalConfig{}
err = json.Unmarshal(globalConfigData, config)
if err != nil {
return nil, err
}
return config, nil
}
// ReadAdminUIConfig 读取管理员界面配置
func (this *SysSettingDAO) ReadAdminUIConfig(tx *dbs.Tx, cacheMap *utils.CacheMap) (*systemconfigs.AdminUIConfig, error) {
var cacheKey = this.Table + ":ReadAdminUIConfig"

View File

@@ -428,6 +428,20 @@ func (this *UserDAO) CheckUserEmailPassword(tx *dbs.Tx, verifiedEmail string, en
FindInt64Col(0)
}
// CheckUserMobilePassword 检查邮箱+密码
func (this *UserDAO) CheckUserMobilePassword(tx *dbs.Tx, verifiedEmail string, encryptedPassword string) (int64, error) {
if len(verifiedEmail) == 0 || len(encryptedPassword) == 0 {
return 0, nil
}
return this.Query(tx).
Attr("verifiedMobile", verifiedEmail).
Attr("password", encryptedPassword).
Attr("state", UserStateEnabled).
Attr("isOn", true).
ResultPk().
FindInt64Col(0)
}
// FindUserClusterId 查找用户所在集群
func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error) {
return this.Query(tx).
@@ -663,7 +677,7 @@ func (this *UserDAO) RenewUserServersState(tx *dbs.Tx, userId int64) (bool, erro
// FindUserIdWithVerifiedEmail 使用验证后Email查找用户ID
func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail string) (int64, error) {
if len(verifiedEmail) == 0 {
return 0, nil
}
return this.Query(tx).
ResultPk().
@@ -672,6 +686,18 @@ func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail strin
FindInt64Col(0)
}
// FindUserIdWithVerifiedMobile 使用验证后手机号码查找用户ID
func (this *UserDAO) FindUserIdWithVerifiedMobile(tx *dbs.Tx, verifiedMobile string) (int64, error) {
if len(verifiedMobile) == 0 {
return 0, nil
}
return this.Query(tx).
ResultPk().
State(UserStateEnabled).
Attr("verifiedMobile", verifiedMobile).
FindInt64Col(0)
}
// UpdateUserVerifiedEmail 修改已激活邮箱
func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedEmail string) error {
if userId <= 0 {
@@ -684,6 +710,18 @@ func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedE
UpdateQuickly()
}
// UpdateUserVerifiedMobile 修改已激活手机号码
func (this *UserDAO) UpdateUserVerifiedMobile(tx *dbs.Tx, userId int64, verifiedMobile string) error {
if userId <= 0 {
return nil
}
return this.Query(tx).
Pk(userId).
Set("verifiedMobile", verifiedMobile).
Set("mobileIsVerified", true).
UpdateQuickly()
}
// FindUserBandwidthAlgoForView 获取用户浏览用的带宽算法
func (this *UserDAO) FindUserBandwidthAlgoForView(tx *dbs.Tx, userId int64, uiConfig *systemconfigs.UserUIConfig) (bandwidthAlgo string, err error) {
bandwidthAlgo, err = this.Query(tx).

View File

@@ -0,0 +1,28 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
type UserMobileVerificationDAO dbs.DAO
func NewUserMobileVerificationDAO() *UserMobileVerificationDAO {
return dbs.NewDAO(&UserMobileVerificationDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserMobileVerifications",
Model: new(UserMobileVerification),
PkName: "id",
},
}).(*UserMobileVerificationDAO)
}
var SharedUserMobileVerificationDAO *UserMobileVerificationDAO
func init() {
dbs.OnReady(func() {
SharedUserMobileVerificationDAO = NewUserMobileVerificationDAO()
})
}

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,41 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
UserMobileVerificationField_Id dbs.FieldName = "id" // ID
UserMobileVerificationField_Mobile dbs.FieldName = "mobile" // 手机号码
UserMobileVerificationField_UserId dbs.FieldName = "userId" // 用户ID
UserMobileVerificationField_Code dbs.FieldName = "code" // 激活码
UserMobileVerificationField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
UserMobileVerificationField_IsSent dbs.FieldName = "isSent" // 是否已发送
UserMobileVerificationField_IsVerified dbs.FieldName = "isVerified" // 是否已激活
UserMobileVerificationField_Day dbs.FieldName = "day" // YYYYMMDD
)
// UserMobileVerification 邮箱激活邮件队列
type UserMobileVerification struct {
Id uint64 `field:"id"` // ID
Mobile string `field:"mobile"` // 手机号码
UserId uint64 `field:"userId"` // 用户ID
Code string `field:"code"` // 激活码
CreatedAt uint64 `field:"createdAt"` // 创建时间
IsSent bool `field:"isSent"` // 是否已发送
IsVerified bool `field:"isVerified"` // 是否已激活
Day string `field:"day"` // YYYYMMDD
}
type UserMobileVerificationOperator struct {
Id any // ID
Mobile any // 手机号码
UserId any // 用户ID
Code any // 激活码
CreatedAt any // 创建时间
IsSent any // 是否已发送
IsVerified any // 是否已激活
Day any // YYYYMMDD
}
func NewUserMobileVerificationOperator() *UserMobileVerificationOperator {
return &UserMobileVerificationOperator{}
}

View File

@@ -10,6 +10,7 @@ const (
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
UserField_Mobile dbs.FieldName = "mobile" // 手机号
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
UserField_MobileIsVerified dbs.FieldName = "mobileIsVerified" // 手机号是否已验证
UserField_Tel dbs.FieldName = "tel" // 联系电话
UserField_Remark dbs.FieldName = "remark" // 备注
UserField_Email dbs.FieldName = "email" // 邮箱地址
@@ -47,6 +48,7 @@ type User struct {
Fullname string `field:"fullname"` // 真实姓名
Mobile string `field:"mobile"` // 手机号
VerifiedMobile string `field:"verifiedMobile"` // 已验证手机号
MobileIsVerified uint8 `field:"mobileIsVerified"` // 手机号是否已验证
Tel string `field:"tel"` // 联系电话
Remark string `field:"remark"` // 备注
Email string `field:"email"` // 邮箱地址
@@ -83,6 +85,7 @@ type UserOperator struct {
Fullname any // 真实姓名
Mobile any // 手机号
VerifiedMobile any // 已验证手机号
MobileIsVerified any // 手机号是否已验证
Tel any // 联系电话
Remark any // 备注
Email any // 邮箱地址

View File

@@ -0,0 +1,239 @@
package models
import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"math"
"sync"
"time"
)
type UserPlanBandwidthStatDAO dbs.DAO
const (
UserPlanBandwidthStatTablePartitions = 20 // 分表数量
)
func init() {
dbs.OnReadyDone(func() {
// 清理数据任务
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedUserPlanBandwidthStatDAO.CleanDefaultDays(nil, 100)
if err != nil {
remotelogs.Error("SharedUserPlanBandwidthStatDAO", "clean expired data failed: "+err.Error())
}
}
})
})
}
func NewUserPlanBandwidthStatDAO() *UserPlanBandwidthStatDAO {
return dbs.NewDAO(&UserPlanBandwidthStatDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserPlanBandwidthStats",
Model: new(UserPlanBandwidthStat),
PkName: "id",
},
}).(*UserPlanBandwidthStatDAO)
}
var SharedUserPlanBandwidthStatDAO *UserPlanBandwidthStatDAO
func init() {
dbs.OnReady(func() {
SharedUserPlanBandwidthStatDAO = NewUserPlanBandwidthStatDAO()
})
}
// UpdateUserPlanBandwidth 写入数据
// 暂时不使用region区分
func (this *UserPlanBandwidthStatDAO) UpdateUserPlanBandwidth(tx *dbs.Tx, userId int64, userPlanId int64, regionId int64, day string, timeAt string, bandwidthBytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
if userId <= 0 || userPlanId <= 0 {
return nil
}
return this.Query(tx).
Table(this.partialTable(userPlanId)).
Param("bytes", bandwidthBytes).
Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
InsertOrUpdateQuickly(maps.Map{
"userId": userId,
"userPlanId": userPlanId,
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bandwidthBytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
"attackBytes": attackBytes,
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
"attackBytes": dbs.SQL("attackBytes+:attackBytes"),
"countRequests": dbs.SQL("countRequests+:countRequests"),
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
"countAttackRequests": dbs.SQL("countAttackRequests+:countAttackRequests"),
})
}
// FindMonthlyPercentile 获取某月内百分位
func (this *UserPlanBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, userPlanId int64, month string, percentile int, useAvg bool) (result int64, err error) {
if percentile <= 0 {
percentile = 95
}
// 如果是100%以上,则快速返回
if percentile >= 100 {
result, err = this.Query(tx).
Table(this.partialTable(userPlanId)).
Attr("userPlanId", userPlanId).
Result(this.sumBytesField(useAvg)).
Between("day", month+"01", month+"31").
Group("day").
Group("timeAt").
Desc("bytes").
Limit(1).
FindInt64Col(0)
return
}
// 总数量
total, err := this.Query(tx).
Table(this.partialTable(userPlanId)).
Attr("userPlanId", userPlanId).
Between("day", month+"01", month+"31").
CountAttr("DISTINCT day, timeAt")
if err != nil {
return 0, err
}
if total == 0 {
return 0, nil
}
var offset int64
if total > 1 {
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
}
// 查询 nth 位置
result, err = this.Query(tx).
Table(this.partialTable(userPlanId)).
Attr("userPlanId", userPlanId).
Result(this.sumBytesField(useAvg)).
Between("day", month+"01", month+"31").
Group("day").
Group("timeAt").
Desc("bytes").
Offset(offset).
Limit(1).
FindInt64Col(0)
return
}
// SumMonthlyBytes 读取单月总流量
func (this *UserPlanBandwidthStatDAO) SumMonthlyBytes(tx *dbs.Tx, userPlanId int64, month string) (int64, error) {
if !regexputils.YYYYMM.MatchString(month) {
return 0, errors.New("invalid ")
}
return this.Query(tx).
Table(this.partialTable(userPlanId)).
Attr("userPlanId", userPlanId).
Between("day", month+"01", month+"31").
SumInt64("totalBytes", 0)
}
// CleanDefaultDays 清理过期数据
func (this *UserPlanBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.UserPlanBandwidthStat.Clean.Days > 0 {
defaultDays = databaseConfig.UserPlanBandwidthStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 100
}
return this.CleanDays(tx, defaultDays)
}
// CleanDays 清理过期数据
func (this *UserPlanBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx).
Table(table).
Lt("day", day).
Delete()
return err
})
}
// 获取字节字段
func (this *UserPlanBandwidthStatDAO) bytesField(useAvg bool) string {
if useAvg {
return "avgBytes AS bytes"
}
return "bytes"
}
func (this *UserPlanBandwidthStatDAO) sumBytesField(useAvg bool) string {
if useAvg {
return "SUM(avgBytes) AS bytes"
}
return "SUM(bytes) AS bytes"
}
// 批量执行
func (this *UserPlanBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
var wg = sync.WaitGroup{}
wg.Add(UserPlanBandwidthStatTablePartitions)
var resultErr error
for i := 0; i < UserPlanBandwidthStatTablePartitions; i++ {
var table = this.partialTable(int64(i))
go func(table string) {
defer wg.Done()
err := f(table, locker)
if err != nil {
resultErr = err
}
}(table)
}
wg.Wait()
return resultErr
}
// 获取分区表
func (this *UserPlanBandwidthStatDAO) partialTable(userPlanId int64) string {
return this.Table + "_" + types.String(userPlanId%int64(UserPlanBandwidthStatTablePartitions))
}

View File

@@ -0,0 +1,39 @@
package models_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing"
)
func TestUserPlanBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
var dao = models.NewUserPlanBandwidthStatDAO()
var tx *dbs.Tx
{
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 100, false)
if err != nil {
t.Fatal(err)
}
t.Log("result bytes0:", resultBytes)
}
{
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 95, false)
if err != nil {
t.Fatal(err)
}
t.Log("result bytes1:", resultBytes)
}
{
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 95, true)
if err != nil {
t.Fatal(err)
}
t.Log("result bytes2:", resultBytes)
}
}

View File

@@ -0,0 +1,59 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
UserPlanBandwidthStatField_Id dbs.FieldName = "id" // ID
UserPlanBandwidthStatField_UserId dbs.FieldName = "userId" // 用户ID
UserPlanBandwidthStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
UserPlanBandwidthStatField_Day dbs.FieldName = "day" // 日期YYYYMMDD
UserPlanBandwidthStatField_TimeAt dbs.FieldName = "timeAt" // 时间点HHII
UserPlanBandwidthStatField_Bytes dbs.FieldName = "bytes" // 带宽
UserPlanBandwidthStatField_RegionId dbs.FieldName = "regionId" // 区域ID
UserPlanBandwidthStatField_TotalBytes dbs.FieldName = "totalBytes" // 总流量
UserPlanBandwidthStatField_AvgBytes dbs.FieldName = "avgBytes" // 平均流量
UserPlanBandwidthStatField_CachedBytes dbs.FieldName = "cachedBytes" // 缓存的流量
UserPlanBandwidthStatField_AttackBytes dbs.FieldName = "attackBytes" // 攻击流量
UserPlanBandwidthStatField_CountRequests dbs.FieldName = "countRequests" // 请求数
UserPlanBandwidthStatField_CountCachedRequests dbs.FieldName = "countCachedRequests" // 缓存的请求数
UserPlanBandwidthStatField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 攻击请求数
)
// UserPlanBandwidthStat 用户套餐带宽峰值
type UserPlanBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHII
Bytes uint64 `field:"bytes"` // 带宽
RegionId uint32 `field:"regionId"` // 区域ID
TotalBytes uint64 `field:"totalBytes"` // 总流量
AvgBytes uint64 `field:"avgBytes"` // 平均流量
CachedBytes uint64 `field:"cachedBytes"` // 缓存的流量
AttackBytes uint64 `field:"attackBytes"` // 攻击流量
CountRequests uint64 `field:"countRequests"` // 请求数
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
CountAttackRequests uint64 `field:"countAttackRequests"` // 攻击请求数
}
type UserPlanBandwidthStatOperator struct {
Id any // ID
UserId any // 用户ID
UserPlanId any // 用户套餐ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHII
Bytes any // 带宽
RegionId any // 区域ID
TotalBytes any // 总流量
AvgBytes any // 平均流量
CachedBytes any // 缓存的流量
AttackBytes any // 攻击流量
CountRequests any // 请求数
CountCachedRequests any // 缓存的请求数
CountAttackRequests any // 攻击请求数
}
func NewUserPlanBandwidthStatOperator() *UserPlanBandwidthStatOperator {
return &UserPlanBandwidthStatOperator{}
}

View File

@@ -0,0 +1 @@
package models

View File

@@ -1 +1,8 @@
package models
import timeutil "github.com/iwind/TeaGo/utils/time"
// IsExpired 判断套餐是否过期
func (this *UserPlan) IsExpired() bool {
return len(this.DayTo) == 0 || this.DayTo < timeutil.Format("Y-m-d")
}

View File

@@ -0,0 +1,28 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
type UserPlanStatDAO dbs.DAO
func NewUserPlanStatDAO() *UserPlanStatDAO {
return dbs.NewDAO(&UserPlanStatDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserPlanStats",
Model: new(UserPlanStat),
PkName: "id",
},
}).(*UserPlanStatDAO)
}
var SharedUserPlanStatDAO *UserPlanStatDAO
func init() {
dbs.OnReady(func() {
SharedUserPlanStatDAO = NewUserPlanStatDAO()
})
}

View File

@@ -0,0 +1,10 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import "github.com/iwind/TeaGo/dbs"
func (this *UserPlanStatDAO) IncreaseUserPlanStat(tx *dbs.Tx, userPlanId int64, trafficBytes int64, countRequests int64) error {
return nil
}

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,38 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
UserPlanStatField_Id dbs.FieldName = "id" // ID
UserPlanStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
UserPlanStatField_Date dbs.FieldName = "date" // 日期YYYYMMDD或YYYYMM
UserPlanStatField_DateType dbs.FieldName = "dateType" // 日期类型day|month
UserPlanStatField_TrafficBytes dbs.FieldName = "trafficBytes" // 流量
UserPlanStatField_CountRequests dbs.FieldName = "countRequests" // 总请求数
UserPlanStatField_IsProcessed dbs.FieldName = "isProcessed" // 是否已处理
)
// UserPlanStat 用户套餐统计
type UserPlanStat struct {
Id uint64 `field:"id"` // ID
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
Date string `field:"date"` // 日期YYYYMMDD或YYYYMM
DateType string `field:"dateType"` // 日期类型day|month
TrafficBytes uint64 `field:"trafficBytes"` // 流量
CountRequests uint64 `field:"countRequests"` // 总请求数
IsProcessed bool `field:"isProcessed"` // 是否已处理
}
type UserPlanStatOperator struct {
Id any // ID
UserPlanId any // 用户套餐ID
Date any // 日期YYYYMMDD或YYYYMM
DateType any // 日期类型day|month
TrafficBytes any // 流量
CountRequests any // 总请求数
IsProcessed any // 是否已处理
}
func NewUserPlanStatOperator() *UserPlanStatOperator {
return &UserPlanStatOperator{}
}

View File

@@ -0,0 +1 @@
package models

View File

@@ -55,7 +55,9 @@ func (this *CustomHTTPProvider) Auth(params maps.Map) error {
// GetDomains 获取所有域名列表
func (this *CustomHTTPProvider) GetDomains() (domains []string, err error) {
resp, err := this.post(maps.Map{})
resp, err := this.post(maps.Map{
"action": "GetDomains",
})
if err != nil {
return nil, err
}

View File

@@ -32,8 +32,6 @@ var dnsPodHTTPClient = &http.Client{
}
// DNSPodProvider DNSPod服务商
// TODO 考虑支持线路ID
// TODO 支持自定义线路
type DNSPodProvider struct {
BaseProvider
@@ -42,19 +40,30 @@ type DNSPodProvider struct {
region string
apiId string
apiToken string
tencentDNSProvider *TencentDNSProvider
}
// Auth 认证
func (this *DNSPodProvider) Auth(params maps.Map) error {
this.apiId = params.GetString("id")
this.apiToken = params.GetString("token")
this.region = params.GetString("region")
// 兼容腾讯云API
var apiType = params.GetString("apiType")
if len(this.apiId) == 0 {
return errors.New("'id' should be not empty")
}
if len(this.apiToken) == 0 {
return errors.New("'token' should not be empty")
switch apiType {
case "tencentDNS":
this.tencentDNSProvider = NewTencentDNSProvider()
return this.tencentDNSProvider.Auth(params)
default:
this.apiId = params.GetString("id")
this.apiToken = params.GetString("token")
this.region = params.GetString("region")
if len(this.apiId) == 0 {
return errors.New("'id' should be not empty")
}
if len(this.apiToken) == 0 {
return errors.New("'token' should not be empty")
}
}
return nil
@@ -62,6 +71,10 @@ func (this *DNSPodProvider) Auth(params maps.Map) error {
// GetDomains 获取所有域名列表
func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetDomains()
}
var offset = 0
var size = 3000
@@ -92,6 +105,10 @@ func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
// GetRecords 获取域名列表
func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetRecords(domain)
}
var offset = 0
var size = 3000
for {
@@ -135,6 +152,10 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
// GetRoutes 读取线路数据
func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetRoutes(domain)
}
var domainInfoResp = new(dnspod.DomainInfoResponse)
err = this.doAPI("/Domain.Info", map[string]string{
"domain": domain,
@@ -217,6 +238,10 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
// QueryRecord 查询单个记录
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.QueryRecord(domain, name, recordType)
}
// 从缓存中读取
if this.ProviderId > 0 {
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
@@ -239,6 +264,10 @@ func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType d
// QueryRecords 查询多个记录
func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.QueryRecords(domain, name, recordType)
}
// 从缓存中读取
if this.ProviderId > 0 {
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
@@ -262,6 +291,10 @@ func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType
// AddRecord 设置记录
func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.AddRecord(domain, newRecord)
}
if newRecord == nil {
return errors.New("invalid new record")
}
@@ -298,6 +331,10 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
// UpdateRecord 修改记录
func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.UpdateRecord(domain, record, newRecord)
}
if record == nil {
return errors.New("invalid record")
}
@@ -339,6 +376,10 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
// DeleteRecord 删除记录
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.DeleteRecord(domain, record)
}
if record == nil {
return errors.New("invalid record to delete")
}
@@ -412,6 +453,10 @@ func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr
// DefaultRoute 默认线路
func (this *DNSPodProvider) DefaultRoute() string {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.DefaultRoute()
}
if this.isInternational() {
return "Default"
}

View File

@@ -0,0 +1,409 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsclients
import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
tencenterrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
"strings"
)
// TencentDNSProvider 腾讯云DNS云解析
type TencentDNSProvider struct {
BaseProvider
ProviderId int64
client *dnspod.Client
}
func NewTencentDNSProvider() *TencentDNSProvider {
return &TencentDNSProvider{}
}
// Auth 认证
func (this *TencentDNSProvider) Auth(params maps.Map) error {
var accessKeyId = params.GetString("accessKeyId")
var accessKeySecret = params.GetString("accessKeySecret")
if len(accessKeyId) == 0 {
return errors.New("'accessKeyId' required")
}
if len(accessKeySecret) == 0 {
return errors.New("'accessKeySecret' required")
}
client, err := dnspod.NewClient(common.NewCredential(accessKeyId, accessKeySecret), "", profile.NewClientProfile())
if err != nil {
return err
}
this.client = client
return nil
}
// GetDomains 获取所有域名列表
func (this *TencentDNSProvider) GetDomains() (domains []string, err error) {
var offset int64 = 0
var limit int64 = 1000
for {
var req = dnspod.NewDescribeDomainListRequest()
req.Offset = this.int64Val(offset)
req.Limit = this.int64Val(limit)
resp, respErr := this.client.DescribeDomainList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countDomains = len(resp.Response.DomainList)
if countDomains == 0 {
break
}
for _, domainObj := range resp.Response.DomainList {
domains = append(domains, *domainObj.Name)
}
offset += int64(countDomains)
}
return
}
// GetRecords 获取域名列表
func (this *TencentDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
var offset uint64 = 0
var limit uint64 = 1000
for {
var req = dnspod.NewDescribeRecordListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
resp, respErr := this.client.DescribeRecordList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
break
}
for _, recordObj := range resp.Response.RecordList {
records = append(records, &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
})
}
offset += uint64(countRecords)
}
// 写入缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.WriteDomainRecords(this.ProviderId, domain, records)
}
return
}
// GetRoutes 读取线路数据
func (this *TencentDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
// 等级信息
var domainGrade string
{
var req = dnspod.NewDescribeDomainRequest()
req.Domain = this.stringVal(domain)
resp, respErr := this.client.DescribeDomain(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
return
}
return nil, respErr
}
if resp.Response.DomainInfo == nil {
return
}
domainGrade = *resp.Response.DomainInfo.Grade
}
// 等级允许的线路
{
var req = dnspod.NewDescribeRecordLineListRequest()
req.Domain = this.stringVal(domain)
req.DomainGrade = this.stringVal(domainGrade)
resp, respErr := this.client.DescribeRecordLineList(req)
if respErr != nil {
return nil, respErr
}
for _, lineGroupObj := range resp.Response.LineGroupList {
routes = append(routes, &dnstypes.Route{
Name: "Group:" + *lineGroupObj.Name,
Code: *lineGroupObj.LineId,
})
}
for _, lineObj := range resp.Response.LineList {
routes = append(routes, &dnstypes.Route{
Name: *lineObj.Name,
Code: *lineObj.LineId,
})
}
}
return
}
// QueryRecord 查询单个记录
func (this *TencentDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
// 从缓存中读取
if this.ProviderId > 0 {
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
if hasRecords { // 有效的搜索
return record, nil
}
}
var offset uint64 = 0
var limit uint64 = 1000
var req = dnspod.NewDescribeRecordFilterListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
req.SubDomain = this.stringVal(name)
req.RecordType = []*string{this.stringVal(recordType)}
resp, respErr := this.client.DescribeRecordFilterList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
return nil, nil
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
return nil, nil
}
for _, recordObj := range resp.Response.RecordList {
if *recordObj.Name == name && *recordObj.Type == recordType {
return &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
}, nil
}
}
return nil, nil
}
// QueryRecords 查询多个记录
func (this *TencentDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
// 从缓存中读取
if this.ProviderId > 0 {
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
if hasRecords { // 有效的搜索
return records, nil
}
}
var offset uint64 = 0
var limit uint64 = 1000
var records []*dnstypes.Record
for {
var req = dnspod.NewDescribeRecordFilterListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
req.SubDomain = this.stringVal(name)
req.RecordType = []*string{this.stringVal(recordType)}
resp, respErr := this.client.DescribeRecordFilterList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
break
}
for _, recordObj := range resp.Response.RecordList {
records = append(records, &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
})
}
offset += uint64(countRecords)
}
return records, nil
}
// AddRecord 设置记录
func (this *TencentDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
if newRecord == nil {
return errors.New("invalid new record")
}
// 在CHANGE记录后面加入点
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
newRecord.Value += "."
}
var ttl = newRecord.TTL
if ttl <= 0 {
ttl = 600
}
var req = dnspod.NewCreateRecordRequest()
req.Domain = this.stringVal(domain)
req.SubDomain = this.stringVal(newRecord.Name)
req.RecordType = this.stringVal(newRecord.Type)
req.TTL = this.uint64Val(uint64(ttl))
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项但以RecordLineId优先
req.RecordLineId = this.stringVal(newRecord.Route)
req.Value = this.stringVal(newRecord.Value)
resp, respErr := this.client.CreateRecord(req)
if respErr != nil {
return respErr
}
newRecord.Id = types.String(*resp.Response.RecordId)
// 加入缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.AddDomainRecord(this.ProviderId, domain, newRecord)
}
return nil
}
// UpdateRecord 修改记录
func (this *TencentDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
if record == nil {
return errors.New("invalid record")
}
if newRecord == nil {
return errors.New("invalid new record")
}
// 在CHANGE记录后面加入点
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
newRecord.Value += "."
}
var newRoute = newRecord.Route
if len(newRoute) == 0 {
newRoute = this.DefaultRoute()
}
var ttl = newRecord.TTL
if ttl <= 0 {
ttl = 600
}
var req = dnspod.NewModifyRecordRequest()
req.Domain = this.stringVal(domain)
req.RecordId = this.uint64Val(types.Uint64(record.Id))
req.SubDomain = this.stringVal(newRecord.Name)
req.RecordType = this.stringVal(newRecord.Type)
req.TTL = this.uint64Val(uint64(ttl))
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项但以RecordLineId优先
req.RecordLineId = this.stringVal(newRecord.Route)
req.Value = this.stringVal(newRecord.Value)
_, respErr := this.client.ModifyRecord(req)
if respErr != nil {
return respErr
}
// 修改缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.UpdateDomainRecord(this.ProviderId, domain, newRecord)
}
return nil
}
// DeleteRecord 删除记录
func (this *TencentDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
if record == nil {
return errors.New("invalid record to delete")
}
var req = dnspod.NewDeleteRecordRequest()
req.Domain = this.stringVal(domain)
req.RecordId = this.uint64Val(types.Uint64(record.Id))
_, respErr := this.client.DeleteRecord(req)
if respErr != nil {
if len(record.Id) > 0 && this.isRecordInvalidErr(respErr) {
return nil
}
return respErr
}
// 删除缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.DeleteDomainRecord(this.ProviderId, domain, record.Id)
}
return nil
}
// DefaultRoute 默认线路
func (this *TencentDNSProvider) DefaultRoute() string {
return "0"
}
func (this *TencentDNSProvider) DefaultRouteName() string {
return "默认"
}
func (this *TencentDNSProvider) fixCNAME(recordType string, recordValue string) string {
// 修正Record
if strings.ToUpper(recordType) == dnstypes.RecordTypeCNAME && !strings.HasSuffix(recordValue, ".") {
recordValue += "."
}
return recordValue
}
func (this *TencentDNSProvider) int64Val(v int64) *int64 {
return &v
}
func (this *TencentDNSProvider) uint64Val(v uint64) *uint64 {
return &v
}
func (this *TencentDNSProvider) stringVal(s string) *string {
return &s
}
func (this *TencentDNSProvider) isNotFoundErr(err error) bool {
if err == nil {
return false
}
var sdkErr *tencenterrors.TencentCloudSDKError
return errors.As(err, &sdkErr) && strings.HasPrefix(sdkErr.Code, "ResourceNotFound.")
}
func (this *TencentDNSProvider) isRecordInvalidErr(err error) bool {
if err == nil {
return false
}
var sdkErr *tencenterrors.TencentCloudSDKError
return errors.As(err, &sdkErr) && sdkErr.Code == "InvalidParameter.RecordIdInvalid"
}

View File

@@ -26,7 +26,7 @@ func FindAllProviderTypes() []maps.Map {
"description": "阿里云提供的DNS服务。",
},
{
"name": "DNSPod",
"name": "腾讯云DNSPod",
"code": ProviderTypeDNSPod,
"description": "DNSPod提供的DNS服务。",
},
@@ -52,7 +52,7 @@ func FindAllProviderTypes() []maps.Map {
typeMaps = append(typeMaps, maps.Map{
"name": "自定义HTTP DNS",
"code": ProviderTypeCustomHTTP,
"description": "通过自定义的HTTP接口提供DNS服务",
"description": "通过自定义的HTTP接口提供DNS服务具体使用方法请参考官网文档https://goedge.cn/docs/DNS/CustomHTTP.md ",
})
return typeMaps
}

View File

@@ -10,6 +10,10 @@ import (
// FindProvider 查找服务商实例
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
switch providerType {
case ProviderTypeTencentDNS:
return &TencentDNSProvider{
ProviderId: providerId,
}
case ProviderTypeDNSPod:
return &DNSPodProvider{
ProviderId: providerId,

View File

@@ -189,36 +189,6 @@ func (this *APINode) registerServices(server *grpc.Server) {
pb.RegisterMessageServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageRecipientService{}).(*services.MessageRecipientService)
pb.RegisterMessageRecipientServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageReceiverService{}).(*services.MessageReceiverService)
pb.RegisterMessageReceiverServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageRecipientGroupService{}).(*services.MessageRecipientGroupService)
pb.RegisterMessageRecipientGroupServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageMediaInstanceService{}).(*services.MessageMediaInstanceService)
pb.RegisterMessageMediaInstanceServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageTaskService{}).(*services.MessageTaskService)
pb.RegisterMessageTaskServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MessageTaskLogService{}).(*services.MessageTaskLogService)
pb.RegisterMessageTaskLogServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.NodeGroupService{}).(*services.NodeGroupService)
pb.RegisterNodeGroupServiceServer(server, instance)
@@ -454,11 +424,6 @@ func (this *APINode) registerServices(server *grpc.Server) {
pb.RegisterNodeClusterFirewallActionServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.MonitorNodeService{}).(*services.MonitorNodeService)
pb.RegisterMonitorNodeServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.AuthorityNodeService{}).(*services.AuthorityNodeService)
pb.RegisterAuthorityNodeServiceServer(server, instance)

View File

@@ -137,8 +137,8 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
})
// 当前TeaWeb所在的fs
rootFS := ""
rootTotal := uint64(0)
var rootFS = ""
var rootTotal = uint64(0)
if lists.ContainsString([]string{"darwin", "linux", "freebsd"}, runtime.GOOS) {
for _, p := range partitions {
if p.Mountpoint == "/" {
@@ -152,9 +152,9 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
}
}
total := rootTotal
totalUsage := uint64(0)
maxUsage := float64(0)
var total = rootTotal
var totalUsage = uint64(0)
var maxUsage = float64(0)
for _, partition := range partitions {
if runtime.GOOS != "windows" && !strings.Contains(partition.Device, "/") && !strings.Contains(partition.Device, "\\") {
continue
@@ -180,6 +180,8 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
}
}
status.DiskTotal = total
status.DiskUsage = float64(totalUsage) / float64(total)
if total > 0 {
status.DiskUsage = float64(totalUsage) / float64(total)
}
status.DiskMaxUsage = maxUsage / 100
}

View File

@@ -65,7 +65,7 @@ func (this *ACMETaskService) CountAllEnabledACMETasks(ctx context.Context, req *
req.UserId = userId
}
count, err := acmemodels.SharedACMETaskDAO.CountAllEnabledACMETasks(tx, req.UserId, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword)
count, err := acmemodels.SharedACMETaskDAO.CountAllEnabledACMETasks(tx, req.UserId, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, req.UserOnly)
if err != nil {
return nil, err
}
@@ -85,7 +85,7 @@ func (this *ACMETaskService) ListEnabledACMETasks(ctx context.Context, req *pb.L
req.UserId = userId
}
tasks, err := acmemodels.SharedACMETaskDAO.ListEnabledACMETasks(tx, req.UserId, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, req.Offset, req.Size)
tasks, err := acmemodels.SharedACMETaskDAO.ListEnabledACMETasks(tx, req.UserId, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, req.UserOnly, req.Offset, req.Size)
if err != nil {
return nil, err
}
@@ -255,7 +255,7 @@ func (this *ACMETaskService) UpdateACMETask(ctx context.Context, req *pb.UpdateA
var tx = this.NullTx()
canAccess, err := acmemodels.SharedACMETaskDAO.CheckACMETask(tx, userId, req.AcmeTaskId)
canAccess, err := acmemodels.SharedACMETaskDAO.CheckUserACMETask(tx, userId, req.AcmeTaskId)
if err != nil {
return nil, err
}
@@ -279,7 +279,7 @@ func (this *ACMETaskService) DeleteACMETask(ctx context.Context, req *pb.DeleteA
var tx = this.NullTx()
canAccess, err := acmemodels.SharedACMETaskDAO.CheckACMETask(tx, userId, req.AcmeTaskId)
canAccess, err := acmemodels.SharedACMETaskDAO.CheckUserACMETask(tx, userId, req.AcmeTaskId)
if err != nil {
return nil, err
}
@@ -303,7 +303,7 @@ func (this *ACMETaskService) RunACMETask(ctx context.Context, req *pb.RunACMETas
var tx = this.NullTx()
canAccess, err := acmemodels.SharedACMETaskDAO.CheckACMETask(tx, userId, req.AcmeTaskId)
canAccess, err := acmemodels.SharedACMETaskDAO.CheckUserACMETask(tx, userId, req.AcmeTaskId)
if err != nil {
return nil, err
}
@@ -329,7 +329,7 @@ func (this *ACMETaskService) FindEnabledACMETask(ctx context.Context, req *pb.Fi
var tx = this.NullTx()
canAccess, err := acmemodels.SharedACMETaskDAO.CheckACMETask(tx, userId, req.AcmeTaskId)
canAccess, err := acmemodels.SharedACMETaskDAO.CheckUserACMETask(tx, userId, req.AcmeTaskId)
if err != nil {
return nil, err
}
@@ -440,3 +440,40 @@ func (this *ACMETaskService) FindEnabledACMETask(ctx context.Context, req *pb.Fi
SslCert: pbCert,
}}, nil
}
// FindACMETaskUser 查找任务所属用户
func (this *ACMETaskService) FindACMETaskUser(ctx context.Context, req *pb.FindACMETaskUserRequest) (*pb.FindACMETaskUserResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
userId, err := acmemodels.SharedACMETaskDAO.FindACMETaskUserId(tx, req.AcmeTaskId)
if err != nil {
return nil, err
}
if userId <= 0 {
return &pb.FindACMETaskUserResponse{User: nil}, nil
}
user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, userId)
if err != nil {
return nil, err
}
if user == nil {
return &pb.FindACMETaskUserResponse{
User: &pb.User{
Id: userId,
},
}, nil
}
return &pb.FindACMETaskUserResponse{
User: &pb.User{
Id: userId,
Username: user.Username,
Fullname: user.Fullname,
},
}, nil
}

View File

@@ -549,7 +549,7 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
result.CountServers = countServers
this.BeginTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
countAuditingServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", 0, 0, configutils.BoolStateYes, nil)
countAuditingServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", 0, 0, configutils.BoolStateYes, nil, 0)
this.EndTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
if err != nil {
return nil, err

View File

@@ -78,7 +78,7 @@ func (this *APINodeService) DeleteAPINode(ctx context.Context, req *pb.DeleteAPI
// FindAllEnabledAPINodes 列出所有可用API节点
func (this *APINodeService) FindAllEnabledAPINodes(ctx context.Context, req *pb.FindAllEnabledAPINodesRequest) (*pb.FindAllEnabledAPINodesResponse, error) {
_, _, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser, rpcutils.UserTypeNode, rpcutils.UserTypeMonitor, rpcutils.UserTypeDNS, rpcutils.UserTypeAuthority)
_, _, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser, rpcutils.UserTypeNode, rpcutils.UserTypeDNS, rpcutils.UserTypeAuthority)
if err != nil {
return nil, err
}

View File

@@ -95,12 +95,6 @@ func (this *BaseService) ValidateUserNode(ctx context.Context, canRest bool) (us
return
}
// ValidateMonitorNode 校验监控节点
func (this *BaseService) ValidateMonitorNode(ctx context.Context) (nodeId int64, err error) {
_, _, nodeId, err = rpcutils.ValidateRequest(ctx, rpcutils.UserTypeMonitor)
return
}
// ValidateAuthorityNode 校验认证节点
func (this *BaseService) ValidateAuthorityNode(ctx context.Context) (nodeId int64, err error) {
_, _, nodeId, err = rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAuthority)
@@ -111,7 +105,7 @@ func (this *BaseService) ValidateAuthorityNode(ctx context.Context) (nodeId int6
func (this *BaseService) ValidateNodeId(ctx context.Context, roles ...rpcutils.UserType) (role rpcutils.UserType, nodeIntId int64, err error) {
// 默认包含大部分节点
if len(roles) == 0 {
roles = []rpcutils.UserType{rpcutils.UserTypeNode, rpcutils.UserTypeCluster, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser, rpcutils.UserTypeDNS, rpcutils.UserTypeReport, rpcutils.UserTypeMonitor, rpcutils.UserTypeLog, rpcutils.UserTypeAPI}
roles = []rpcutils.UserType{rpcutils.UserTypeNode, rpcutils.UserTypeCluster, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser, rpcutils.UserTypeDNS, rpcutils.UserTypeReport, rpcutils.UserTypeLog, rpcutils.UserTypeAPI}
}
if ctx == nil {
@@ -195,8 +189,6 @@ func (this *BaseService) ValidateNodeId(ctx context.Context, roles ...rpcutils.U
nodeIntId, err = models.SharedUserNodeDAO.FindEnabledUserNodeIdWithUniqueId(nil, nodeId)
case rpcutils.UserTypeAdmin:
nodeIntId = 0
case rpcutils.UserTypeMonitor:
nodeIntId, err = models.SharedMonitorNodeDAO.FindEnabledMonitorNodeIdWithUniqueId(nil, nodeId)
case rpcutils.UserTypeDNS:
nodeIntId, err = models.SharedNSNodeDAO.FindEnabledNodeIdWithUniqueId(nil, nodeId)
case rpcutils.UserTypeReport:

View File

@@ -31,9 +31,11 @@ func (this *HTTPAccessLogService) CreateHTTPAccessLogs(ctx context.Context, req
var tx = this.NullTx()
err = models.SharedHTTPAccessLogDAO.CreateHTTPAccessLogs(tx, req.HttpAccessLogs)
if err != nil {
return nil, err
if this.canWriteAccessLogsToDB() {
err = models.SharedHTTPAccessLogDAO.CreateHTTPAccessLogs(tx, req.HttpAccessLogs)
if err != nil {
return nil, err
}
}
err = this.writeAccessLogsToPolicy(req.HttpAccessLogs)

View File

@@ -5,6 +5,10 @@ package services
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
func (this *HTTPAccessLogService) canWriteAccessLogsToDB() bool {
return true
}
func (this *HTTPAccessLogService) writeAccessLogsToPolicy(pbAccessLogs []*pb.HTTPAccessLog) error {
return nil
}

View File

@@ -86,7 +86,7 @@ func (this *HTTPFirewallRuleSetService) FindEnabledHTTPFirewallRuleSetConfig(ctx
var tx = this.NullTx()
config, err := models.SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, req.FirewallRuleSetId)
config, err := models.SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, req.FirewallRuleSetId, false)
if err != nil {
return nil, err
}

View File

@@ -4,9 +4,11 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/types"
)
@@ -30,7 +32,7 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
const maxBodyLength = 32 * 1024
switch req.BodyType {
case shared.BodyTypeURL:
case serverconfigs.HTTPPageBodyTypeURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
@@ -41,7 +43,18 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case shared.BodyTypeHTML:
case serverconfigs.HTTPPageBodyTypeRedirectURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
if !regexputils.HTTPProtocol.MatchString(req.Url) {
return nil, errors.New("invalid 'url' format")
}
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case serverconfigs.HTTPPageBodyTypeHTML:
if len(req.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}
@@ -53,7 +66,35 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
}
pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
var exceptURLPatterns = []*shared.URLPattern{}
if len(req.ExceptURLPatternsJSON) > 0 {
err = json.Unmarshal(req.ExceptURLPatternsJSON, &exceptURLPatterns)
if err != nil {
return nil, err
}
for _, pattern := range exceptURLPatterns {
err = pattern.Init()
if err != nil {
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
}
}
}
var onlyURLPatterns = []*shared.URLPattern{}
if len(req.OnlyURLPatternsJSON) > 0 {
err = json.Unmarshal(req.OnlyURLPatternsJSON, &onlyURLPatterns)
if err != nil {
return nil, err
}
for _, pattern := range onlyURLPatterns {
err = pattern.Init()
if err != nil {
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
}
}
}
pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus), exceptURLPatterns, onlyURLPatterns)
if err != nil {
return nil, err
}
@@ -82,7 +123,7 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
const maxBodyLength = 32 * 1024
switch req.BodyType {
case shared.BodyTypeURL:
case serverconfigs.HTTPPageBodyTypeURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
@@ -93,7 +134,18 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case shared.BodyTypeHTML:
case serverconfigs.HTTPPageBodyTypeRedirectURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
if !regexputils.HTTPProtocol.MatchString(req.Url) {
return nil, errors.New("invalid 'url' format")
}
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case serverconfigs.HTTPPageBodyTypeHTML:
if len(req.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}
@@ -105,7 +157,35 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
}
err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
var exceptURLPatterns = []*shared.URLPattern{}
if len(req.ExceptURLPatternsJSON) > 0 {
err = json.Unmarshal(req.ExceptURLPatternsJSON, &exceptURLPatterns)
if err != nil {
return nil, err
}
for _, pattern := range exceptURLPatterns {
err = pattern.Init()
if err != nil {
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
}
}
}
var onlyURLPatterns = []*shared.URLPattern{}
if len(req.OnlyURLPatternsJSON) > 0 {
err = json.Unmarshal(req.OnlyURLPatternsJSON, &onlyURLPatterns)
if err != nil {
return nil, err
}
for _, pattern := range onlyURLPatterns {
err = pattern.Init()
if err != nil {
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
}
}
}
err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus), exceptURLPatterns, onlyURLPatterns)
if err != nil {
return nil, err
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/dbs"
)
@@ -365,7 +364,7 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
}
switch shutdownConfig.BodyType {
case shared.BodyTypeURL:
case serverconfigs.HTTPPageBodyTypeURL:
if len(shutdownConfig.URL) > maxURLLength {
return nil, errors.New("'url' too long")
}
@@ -376,7 +375,18 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
shutdownConfig.Body = ""
}
case shared.BodyTypeHTML:
case serverconfigs.HTTPPageBodyTypeRedirectURL:
if len(shutdownConfig.URL) > maxURLLength {
return nil, errors.New("'url' too long")
}
if shutdownConfig.IsOn /** validate when it's on **/ && !regexputils.HTTPProtocol.MatchString(shutdownConfig.URL) {
return nil, errors.New("invalid 'url' format")
}
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
shutdownConfig.Body = ""
}
case serverconfigs.HTTPPageBodyTypeHTML:
if len(shutdownConfig.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}

View File

@@ -1,187 +0,0 @@
package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// MessageMediaInstanceService 消息媒介实例服务
type MessageMediaInstanceService struct {
BaseService
}
// CreateMessageMediaInstance 创建消息媒介实例
func (this *MessageMediaInstanceService) CreateMessageMediaInstance(ctx context.Context, req *pb.CreateMessageMediaInstanceRequest) (*pb.CreateMessageMediaInstanceResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
params := maps.Map{}
if len(req.ParamsJSON) > 0 {
err = json.Unmarshal(req.ParamsJSON, &params)
if err != nil {
return nil, err
}
}
instanceId, err := models.SharedMessageMediaInstanceDAO.CreateMediaInstance(tx, req.Name, req.MediaType, params, req.Description, req.RateJSON, req.HashLife)
if err != nil {
return nil, err
}
return &pb.CreateMessageMediaInstanceResponse{MessageMediaInstanceId: instanceId}, nil
}
// UpdateMessageMediaInstance 修改消息实例
func (this *MessageMediaInstanceService) UpdateMessageMediaInstance(ctx context.Context, req *pb.UpdateMessageMediaInstanceRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
params := maps.Map{}
if len(req.ParamsJSON) > 0 {
err = json.Unmarshal(req.ParamsJSON, &params)
if err != nil {
return nil, err
}
}
var tx = this.NullTx()
err = models.SharedMessageMediaInstanceDAO.UpdateMediaInstance(tx, req.MessageMediaInstanceId, req.Name, req.MediaType, params, req.Description, req.RateJSON, req.HashLife, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteMessageMediaInstance 删除媒介实例
func (this *MessageMediaInstanceService) DeleteMessageMediaInstance(ctx context.Context, req *pb.DeleteMessageMediaInstanceRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageMediaInstanceDAO.DisableMessageMediaInstance(tx, req.MessageMediaInstanceId)
if err != nil {
return nil, err
}
return this.Success()
}
// CountAllEnabledMessageMediaInstances 计算媒介实例数量
func (this *MessageMediaInstanceService) CountAllEnabledMessageMediaInstances(ctx context.Context, req *pb.CountAllEnabledMessageMediaInstancesRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedMessageMediaInstanceDAO.CountAllEnabledMediaInstances(tx, req.MediaType, req.Keyword)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListEnabledMessageMediaInstances 列出单页媒介实例
func (this *MessageMediaInstanceService) ListEnabledMessageMediaInstances(ctx context.Context, req *pb.ListEnabledMessageMediaInstancesRequest) (*pb.ListEnabledMessageMediaInstancesResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
instances, err := models.SharedMessageMediaInstanceDAO.ListAllEnabledMediaInstances(tx, req.MediaType, req.Keyword, req.Offset, req.Size)
if err != nil {
return nil, err
}
pbInstances := []*pb.MessageMediaInstance{}
for _, instance := range instances {
// 媒介
media, err := models.SharedMessageMediaDAO.FindEnabledMediaWithType(tx, instance.MediaType)
if err != nil {
return nil, err
}
if media == nil {
continue
}
pbMedia := &pb.MessageMedia{
Id: int64(media.Id),
Type: media.Type,
Name: media.Name,
Description: media.Description,
UserDescription: media.UserDescription,
IsOn: media.IsOn,
}
pbInstances = append(pbInstances, &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
IsOn: instance.IsOn,
MessageMedia: pbMedia,
ParamsJSON: instance.Params,
Description: instance.Description,
RateJSON: instance.Rate,
})
}
return &pb.ListEnabledMessageMediaInstancesResponse{MessageMediaInstances: pbInstances}, nil
}
// FindEnabledMessageMediaInstance 查找单个媒介实例信息
func (this *MessageMediaInstanceService) FindEnabledMessageMediaInstance(ctx context.Context, req *pb.FindEnabledMessageMediaInstanceRequest) (*pb.FindEnabledMessageMediaInstanceResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, req.MessageMediaInstanceId, cacheMap)
if err != nil {
return nil, err
}
if instance == nil {
return &pb.FindEnabledMessageMediaInstanceResponse{MessageMediaInstance: nil}, nil
}
// 媒介
media, err := models.SharedMessageMediaDAO.FindEnabledMediaWithType(tx, instance.MediaType)
if err != nil {
return nil, err
}
if media == nil {
return &pb.FindEnabledMessageMediaInstanceResponse{MessageMediaInstance: nil}, nil
}
pbMedia := &pb.MessageMedia{
Id: int64(media.Id),
Type: media.Type,
Name: media.Name,
Description: media.Description,
UserDescription: media.UserDescription,
IsOn: media.IsOn,
}
return &pb.FindEnabledMessageMediaInstanceResponse{MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
IsOn: instance.IsOn,
MessageMedia: pbMedia,
ParamsJSON: instance.Params,
Description: instance.Description,
RateJSON: instance.Rate,
HashLife: types.Int32(instance.HashLife),
}}, nil
}

View File

@@ -1,193 +0,0 @@
package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
)
// MessageReceiverService 消息对象接收人
type MessageReceiverService struct {
BaseService
}
// UpdateMessageReceivers 创建接收者
func (this *MessageReceiverService) UpdateMessageReceivers(ctx context.Context, req *pb.UpdateMessageReceiversRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
if len(req.Role) == 0 {
req.Role = nodeconfigs.NodeRoleNode
}
params := maps.Map{}
if len(req.ParamsJSON) > 0 {
err = json.Unmarshal(req.ParamsJSON, &params)
if err != nil {
return nil, err
}
}
err = this.RunTx(func(tx *dbs.Tx) error {
err = models.SharedMessageReceiverDAO.DisableReceivers(tx, req.NodeClusterId, req.NodeId, req.ServerId)
if err != nil {
return err
}
for messageType, options := range req.RecipientOptions {
for _, option := range options.RecipientOptions {
_, err := models.SharedMessageReceiverDAO.CreateReceiver(tx, req.Role, req.NodeClusterId, req.NodeId, req.ServerId, messageType, params, option.MessageRecipientId, option.MessageRecipientGroupId)
if err != nil {
return err
}
}
}
return nil
})
if err != nil {
return nil, err
}
return this.Success()
}
// FindAllEnabledMessageReceivers 查找接收者
func (this *MessageReceiverService) FindAllEnabledMessageReceivers(ctx context.Context, req *pb.FindAllEnabledMessageReceiversRequest) (*pb.FindAllEnabledMessageReceiversResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
if len(req.Role) == 0 {
req.Role = nodeconfigs.NodeRoleNode
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
receivers, err := models.SharedMessageReceiverDAO.FindAllEnabledReceivers(tx, req.Role, req.NodeClusterId, req.NodeId, req.ServerId, "")
if err != nil {
return nil, err
}
pbReceivers := []*pb.MessageReceiver{}
for _, receiver := range receivers {
var pbRecipient *pb.MessageRecipient = nil
// 接收人
if receiver.RecipientId > 0 {
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, int64(receiver.RecipientId), cacheMap)
if err != nil {
return nil, err
}
if recipient == nil {
continue
}
// 管理员
admin, err := models.SharedAdminDAO.FindEnabledAdmin(tx, int64(recipient.AdminId))
if err != nil {
return nil, err
}
if admin == nil {
continue
}
// 接收人
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil {
continue
}
pbRecipient = &pb.MessageRecipient{
Id: int64(recipient.Id),
Admin: &pb.Admin{
Id: int64(admin.Id),
Fullname: admin.Fullname,
Username: admin.Username,
IsOn: admin.IsOn,
},
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
IsOn: instance.IsOn,
},
IsOn: recipient.IsOn,
MessageRecipientGroups: nil,
Description: "",
User: "",
}
}
// 接收人分组
var pbRecipientGroup *pb.MessageRecipientGroup = nil
if receiver.RecipientGroupId > 0 {
group, err := models.SharedMessageRecipientGroupDAO.FindEnabledMessageRecipientGroup(tx, int64(receiver.RecipientGroupId))
if err != nil {
return nil, err
}
if group == nil {
continue
}
pbRecipientGroup = &pb.MessageRecipientGroup{
Id: int64(group.Id),
Name: group.Name,
IsOn: group.IsOn,
}
}
pbReceivers = append(pbReceivers, &pb.MessageReceiver{
Id: int64(receiver.Id),
ClusterId: int64(receiver.ClusterId),
NodeId: int64(receiver.NodeId),
ServerId: int64(receiver.ServerId),
Type: receiver.Type,
ParamsJSON: receiver.Params,
MessageRecipient: pbRecipient,
MessageRecipientGroup: pbRecipientGroup,
})
}
return &pb.FindAllEnabledMessageReceiversResponse{MessageReceivers: pbReceivers}, nil
}
// DeleteMessageReceiver 删除接收者
func (this *MessageReceiverService) DeleteMessageReceiver(ctx context.Context, req *pb.DeleteMessageReceiverRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageReceiverDAO.DisableMessageReceiver(tx, req.MessageReceiverId)
if err != nil {
return nil, err
}
return this.Success()
}
// CountAllEnabledMessageReceivers 计算接收者数量
func (this *MessageReceiverService) CountAllEnabledMessageReceivers(ctx context.Context, req *pb.CountAllEnabledMessageReceiversRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
if len(req.Role) == 0 {
req.Role = nodeconfigs.NodeRoleNode
}
var tx = this.NullTx()
count, err := models.SharedMessageReceiverDAO.CountAllEnabledReceivers(tx, req.Role, req.NodeClusterId, req.NodeId, req.ServerId, "")
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}

View File

@@ -1,235 +0,0 @@
package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// MessageRecipientService 消息接收人服务
type MessageRecipientService struct {
BaseService
}
// CreateMessageRecipient 创建接收人
func (this *MessageRecipientService) CreateMessageRecipient(ctx context.Context, req *pb.CreateMessageRecipientRequest) (*pb.CreateMessageRecipientResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
recipientId, err := models.SharedMessageRecipientDAO.CreateRecipient(tx, req.AdminId, req.MessageMediaInstanceId, req.User, req.MessageRecipientGroupIds, req.Description, req.TimeFrom, req.TimeTo)
if err != nil {
return nil, err
}
return &pb.CreateMessageRecipientResponse{MessageRecipientId: recipientId}, nil
}
// UpdateMessageRecipient 修改接收人
func (this *MessageRecipientService) UpdateMessageRecipient(ctx context.Context, req *pb.UpdateMessageRecipientRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageRecipientDAO.UpdateRecipient(tx, req.MessageRecipientId, req.AdminId, req.MessageMediaInstanceId, req.User, req.MessageRecipientGroupIds, req.Description, req.TimeFrom, req.TimeTo, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteMessageRecipient 删除接收人
func (this *MessageRecipientService) DeleteMessageRecipient(ctx context.Context, req *pb.DeleteMessageRecipientRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageRecipientDAO.DisableMessageRecipient(tx, req.MessageRecipientId)
if err != nil {
return nil, err
}
return this.Success()
}
// CountAllEnabledMessageRecipients 计算接收人数量
func (this *MessageRecipientService) CountAllEnabledMessageRecipients(ctx context.Context, req *pb.CountAllEnabledMessageRecipientsRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedMessageRecipientDAO.CountAllEnabledRecipients(tx, req.AdminId, req.MessageRecipientGroupId, req.MediaType, req.Keyword)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListEnabledMessageRecipients 列出单页接收人
func (this *MessageRecipientService) ListEnabledMessageRecipients(ctx context.Context, req *pb.ListEnabledMessageRecipientsRequest) (*pb.ListEnabledMessageRecipientsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
recipients, err := models.SharedMessageRecipientDAO.ListAllEnabledRecipients(tx, req.AdminId, req.MessageRecipientGroupId, req.MediaType, req.Keyword, req.Offset, req.Size)
if err != nil {
return nil, err
}
pbRecipients := []*pb.MessageRecipient{}
for _, recipient := range recipients {
// admin
admin, err := models.SharedAdminDAO.FindEnabledAdmin(tx, int64(recipient.AdminId))
if err != nil {
return nil, err
}
if admin == nil {
continue
}
pbAdmin := &pb.Admin{
Id: int64(admin.Id),
Fullname: admin.Fullname,
Username: admin.Username,
IsOn: admin.IsOn,
}
// 媒介实例
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil {
continue
}
pbInstance := &pb.MessageMediaInstance{
Id: int64(instance.Id),
IsOn: instance.IsOn,
Name: instance.Name,
Description: instance.Description,
}
// 分组
pbGroups := []*pb.MessageRecipientGroup{}
groupIds := recipient.DecodeGroupIds()
if len(groupIds) > 0 {
for _, groupId := range groupIds {
group, err := models.SharedMessageRecipientGroupDAO.FindEnabledMessageRecipientGroup(tx, groupId)
if err != nil {
return nil, err
}
if group != nil {
pbGroups = append(pbGroups, &pb.MessageRecipientGroup{
Id: int64(group.Id),
Name: group.Name,
IsOn: group.IsOn,
})
}
}
}
pbRecipients = append(pbRecipients, &pb.MessageRecipient{
Id: int64(recipient.Id),
Admin: pbAdmin,
User: recipient.User,
MessageMediaInstance: pbInstance,
IsOn: recipient.IsOn,
MessageRecipientGroups: pbGroups,
Description: recipient.Description,
TimeFrom: recipient.TimeFrom,
TimeTo: recipient.TimeTo,
})
}
return &pb.ListEnabledMessageRecipientsResponse{MessageRecipients: pbRecipients}, nil
}
// FindEnabledMessageRecipient 查找单个接收人信息
func (this *MessageRecipientService) FindEnabledMessageRecipient(ctx context.Context, req *pb.FindEnabledMessageRecipientRequest) (*pb.FindEnabledMessageRecipientResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, req.MessageRecipientId, cacheMap)
if err != nil {
return nil, err
}
if recipient == nil {
return &pb.FindEnabledMessageRecipientResponse{MessageRecipient: nil}, nil
}
// admin
admin, err := models.SharedAdminDAO.FindEnabledAdmin(tx, int64(recipient.AdminId))
if err != nil {
return nil, err
}
if admin == nil {
return &pb.FindEnabledMessageRecipientResponse{MessageRecipient: nil}, nil
}
pbAdmin := &pb.Admin{
Id: int64(admin.Id),
Fullname: admin.Fullname,
Username: admin.Username,
IsOn: admin.IsOn,
}
// 媒介实例
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil {
return &pb.FindEnabledMessageRecipientResponse{MessageRecipient: nil}, nil
}
pbInstance := &pb.MessageMediaInstance{
Id: int64(instance.Id),
IsOn: instance.IsOn,
Name: instance.Name,
Description: instance.Description,
}
// 分组
pbGroups := []*pb.MessageRecipientGroup{}
groupIds := recipient.DecodeGroupIds()
if len(groupIds) > 0 {
for _, groupId := range groupIds {
group, err := models.SharedMessageRecipientGroupDAO.FindEnabledMessageRecipientGroup(tx, groupId)
if err != nil {
return nil, err
}
if group != nil {
pbGroups = append(pbGroups, &pb.MessageRecipientGroup{
Id: int64(group.Id),
Name: group.Name,
IsOn: group.IsOn,
})
}
}
}
return &pb.FindEnabledMessageRecipientResponse{MessageRecipient: &pb.MessageRecipient{
Id: int64(recipient.Id),
User: recipient.User,
Admin: pbAdmin,
MessageMediaInstance: pbInstance,
IsOn: recipient.IsOn,
MessageRecipientGroups: pbGroups,
Description: recipient.Description,
TimeFrom: recipient.TimeFrom,
TimeTo: recipient.TimeTo,
}}, nil
}

View File

@@ -1,106 +0,0 @@
package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// 消息接收人分组
type MessageRecipientGroupService struct {
BaseService
}
// 创建分组
func (this *MessageRecipientGroupService) CreateMessageRecipientGroup(ctx context.Context, req *pb.CreateMessageRecipientGroupRequest) (*pb.CreateMessageRecipientGroupResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
groupId, err := models.SharedMessageRecipientGroupDAO.CreateGroup(tx, req.Name)
if err != nil {
return nil, err
}
return &pb.CreateMessageRecipientGroupResponse{MessageRecipientGroupId: groupId}, nil
}
// 修改分组
func (this *MessageRecipientGroupService) UpdateMessageRecipientGroup(ctx context.Context, req *pb.UpdateMessageRecipientGroupRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageRecipientGroupDAO.UpdateGroup(tx, req.MessageRecipientGroupId, req.Name, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// 查找所有可用的分组
func (this *MessageRecipientGroupService) FindAllEnabledMessageRecipientGroups(ctx context.Context, req *pb.FindAllEnabledMessageRecipientGroupsRequest) (*pb.FindAllEnabledMessageRecipientGroupsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
groups, err := models.SharedMessageRecipientGroupDAO.FindAllEnabledGroups(tx)
if err != nil {
return nil, err
}
pbGroups := []*pb.MessageRecipientGroup{}
for _, group := range groups {
pbGroups = append(pbGroups, &pb.MessageRecipientGroup{
Id: int64(group.Id),
Name: group.Name,
IsOn: group.IsOn,
})
}
return &pb.FindAllEnabledMessageRecipientGroupsResponse{MessageRecipientGroups: pbGroups}, nil
}
// 删除分组
func (this *MessageRecipientGroupService) DeleteMessageRecipientGroup(ctx context.Context, req *pb.DeleteMessageRecipientGroupRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageRecipientGroupDAO.DisableMessageRecipientGroup(tx, req.MessageRecipientGroupId)
if err != nil {
return nil, err
}
return this.Success()
}
// 查找单个分组信息
func (this *MessageRecipientGroupService) FindEnabledMessageRecipientGroup(ctx context.Context, req *pb.FindEnabledMessageRecipientGroupRequest) (*pb.FindEnabledMessageRecipientGroupResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
group, err := models.SharedMessageRecipientGroupDAO.FindEnabledMessageRecipientGroup(tx, req.MessageRecipientGroupId)
if err != nil {
return nil, err
}
if group == nil {
return &pb.FindEnabledMessageRecipientGroupResponse{MessageRecipientGroup: nil}, nil
}
pbGroup := &pb.MessageRecipientGroup{
Id: int64(group.Id),
IsOn: group.IsOn,
Name: group.Name,
}
return &pb.FindEnabledMessageRecipientGroupResponse{MessageRecipientGroup: pbGroup}, nil
}

View File

@@ -1,409 +0,0 @@
package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// MessageTaskService 消息发送任务服务
type MessageTaskService struct {
BaseService
}
// CreateMessageTask 创建任务
func (this *MessageTaskService) CreateMessageTask(ctx context.Context, req *pb.CreateMessageTaskRequest) (*pb.CreateMessageTaskResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
taskId, err := models.SharedMessageTaskDAO.CreateMessageTask(tx, req.RecipientId, req.InstanceId, req.User, req.Subject, req.Body, req.IsPrimary)
if err != nil {
return nil, err
}
return &pb.CreateMessageTaskResponse{MessageTaskId: taskId}, nil
}
// FindSendingMessageTasks 查找要发送的任务
func (this *MessageTaskService) FindSendingMessageTasks(ctx context.Context, req *pb.FindSendingMessageTasksRequest) (*pb.FindSendingMessageTasksResponse, error) {
_, err := this.ValidateMonitorNode(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
tasks, err := models.SharedMessageTaskDAO.FindSendingMessageTasks(tx, req.Size)
if err != nil {
return nil, err
}
pbTasks := []*pb.MessageTask{}
for _, task := range tasks {
var pbRecipient *pb.MessageRecipient
if task.RecipientId > 0 {
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, int64(task.RecipientId), cacheMap)
if err != nil {
return nil, err
}
if recipient == nil || !recipient.IsOn {
// 如果发送人已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
pbRecipient = &pb.MessageRecipient{
Id: int64(recipient.Id),
User: recipient.User,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
RateJSON: instance.Rate,
},
}
} else { // 没有指定既定的接收人
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(task.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
pbRecipient = &pb.MessageRecipient{
Id: 0,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
RateJSON: instance.Rate,
},
}
}
pbTasks = append(pbTasks, &pb.MessageTask{
Id: int64(task.Id),
MessageRecipient: pbRecipient,
User: task.User,
Subject: task.Subject,
Body: task.Body,
CreatedAt: int64(task.CreatedAt),
Status: types.Int32(task.Status),
SentAt: int64(task.SentAt),
})
}
return &pb.FindSendingMessageTasksResponse{MessageTasks: pbTasks}, nil
}
// UpdateMessageTaskStatus 修改任务状态
func (this *MessageTaskService) UpdateMessageTaskStatus(ctx context.Context, req *pb.UpdateMessageTaskStatusRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateMonitorNode(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
resultJSON := []byte{}
if req.Result != nil {
resultJSON, err = json.Marshal(maps.Map{
"isOk": req.Result.IsOk,
"error": req.Result.Error,
"response": req.Result.Response,
})
if err != nil {
return nil, err
}
}
err = models.SharedMessageTaskDAO.UpdateMessageTaskStatus(tx, req.MessageTaskId, int(req.Status), resultJSON)
if err != nil {
return nil, err
}
// 创建发送记录
if (int(req.Status) == models.MessageTaskStatusSuccess || int(req.Status) == models.MessageTaskStatusFailed) && req.Result != nil {
err = models.SharedMessageTaskLogDAO.CreateLog(tx, req.MessageTaskId, req.Result.IsOk, req.Result.Error, req.Result.Response)
if err != nil {
return nil, err
}
}
return this.Success()
}
// DeleteMessageTask 删除消息任务
func (this *MessageTaskService) DeleteMessageTask(ctx context.Context, req *pb.DeleteMessageTaskRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, req.MessageTaskId)
if err != nil {
return nil, err
}
return this.Success()
}
// FindEnabledMessageTask 读取消息任务状态
func (this *MessageTaskService) FindEnabledMessageTask(ctx context.Context, req *pb.FindEnabledMessageTaskRequest) (*pb.FindEnabledMessageTaskResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
task, err := models.SharedMessageTaskDAO.FindEnabledMessageTask(tx, req.MessageTaskId)
if err != nil {
return nil, err
}
if task == nil {
return &pb.FindEnabledMessageTaskResponse{MessageTask: nil}, nil
}
var pbRecipient *pb.MessageRecipient
if task.RecipientId > 0 {
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, int64(task.RecipientId), cacheMap)
if err != nil {
return nil, err
}
if recipient == nil || !recipient.IsOn {
// 如果发送人已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
return &pb.FindEnabledMessageTaskResponse{MessageTask: nil}, nil
}
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
return &pb.FindEnabledMessageTaskResponse{MessageTask: nil}, nil
}
pbRecipient = &pb.MessageRecipient{
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
},
}
} else { // 没有指定既定的接收人
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(task.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
return &pb.FindEnabledMessageTaskResponse{MessageTask: nil}, nil
}
pbRecipient = &pb.MessageRecipient{
Id: 0,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
},
}
}
var result = &pb.MessageTaskResult{}
if len(task.Result) > 0 {
err = json.Unmarshal(task.Result, result)
if err != nil {
return nil, err
}
}
return &pb.FindEnabledMessageTaskResponse{MessageTask: &pb.MessageTask{
Id: int64(task.Id),
MessageRecipient: pbRecipient,
User: task.User,
Subject: task.Subject,
Body: task.Body,
CreatedAt: int64(task.CreatedAt),
Status: int32(task.Status),
SentAt: int64(task.SentAt),
Result: result,
}}, nil
}
// CountMessageTasksWithStatus 计算某个状态的消息任务数量
func (this *MessageTaskService) CountMessageTasksWithStatus(ctx context.Context, req *pb.CountMessageTasksWithStatusRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedMessageTaskDAO.CountMessageTasksWithStatus(tx, types.Int(req.Status))
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListMessageTasksWithStatus 根据状态列出某页任务
func (this *MessageTaskService) ListMessageTasksWithStatus(ctx context.Context, req *pb.ListMessageTasksWithStatusRequest) (*pb.ListMessageTasksWithStatusResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
tasks, err := models.SharedMessageTaskDAO.ListMessageTasksWithStatus(tx, types.Int(req.Status), req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbTasks = []*pb.MessageTask{}
for _, task := range tasks {
var pbRecipient *pb.MessageRecipient
if task.RecipientId > 0 {
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, int64(task.RecipientId), cacheMap)
if err != nil {
return nil, err
}
if recipient == nil || !recipient.IsOn {
// 如果发送人已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(recipient.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
pbRecipient = &pb.MessageRecipient{
Id: int64(recipient.Id),
User: recipient.User,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
RateJSON: instance.Rate,
},
}
} else { // 没有指定既定的接收人
// 媒介
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(task.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil || !instance.IsOn {
// 如果媒介实例已经删除或者禁用,则删除此消息
err = models.SharedMessageTaskDAO.DisableMessageTask(tx, int64(task.Id))
if err != nil {
return nil, err
}
continue
}
pbRecipient = &pb.MessageRecipient{
Id: 0,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
MessageMedia: &pb.MessageMedia{
Type: instance.MediaType,
},
ParamsJSON: instance.Params,
RateJSON: instance.Rate,
},
}
}
var result = &pb.MessageTaskResult{}
if len(task.Result) > 0 {
err = json.Unmarshal(task.Result, result)
if err != nil {
return nil, err
}
}
pbTasks = append(pbTasks, &pb.MessageTask{
Id: int64(task.Id),
MessageRecipient: pbRecipient,
User: task.User,
Subject: task.Subject,
Body: task.Body,
CreatedAt: int64(task.CreatedAt),
Status: types.Int32(task.Status),
SentAt: int64(task.SentAt),
Result: result,
})
}
return &pb.ListMessageTasksWithStatusResponse{MessageTasks: pbTasks}, nil
}

View File

@@ -1,99 +0,0 @@
package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// MessageTaskLogService 消息发送日志相关服务
type MessageTaskLogService struct {
BaseService
}
// CountMessageTaskLogs 计算日志数量
func (this *MessageTaskLogService) CountMessageTaskLogs(ctx context.Context, req *pb.CountMessageTaskLogsRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedMessageTaskLogDAO.CountLogs(tx)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListMessageTaskLogs 列出当页日志
func (this *MessageTaskLogService) ListMessageTaskLogs(ctx context.Context, req *pb.ListMessageTaskLogsRequest) (*pb.ListMessageTaskLogsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
logs, err := models.SharedMessageTaskLogDAO.ListLogs(tx, req.Offset, req.Size)
if err != nil {
return nil, err
}
pbLogs := []*pb.MessageTaskLog{}
for _, log := range logs {
task, err := models.SharedMessageTaskDAO.FindEnabledMessageTask(tx, int64(log.TaskId))
if err != nil {
return nil, err
}
if task == nil {
continue
}
var pbRecipient *pb.MessageRecipient
if task.RecipientId > 0 {
recipient, err := models.SharedMessageRecipientDAO.FindEnabledMessageRecipient(tx, int64(task.RecipientId), cacheMap)
if err != nil {
return nil, err
}
if recipient != nil {
pbRecipient = &pb.MessageRecipient{
Id: int64(recipient.Id),
User: recipient.User,
}
task.InstanceId = recipient.InstanceId
}
}
instance, err := models.SharedMessageMediaInstanceDAO.FindEnabledMessageMediaInstance(tx, int64(task.InstanceId), cacheMap)
if err != nil {
return nil, err
}
if instance == nil {
continue
}
pbLogs = append(pbLogs, &pb.MessageTaskLog{
Id: int64(log.Id),
CreatedAt: int64(log.CreatedAt),
IsOk: log.IsOk,
Error: log.Error,
Response: log.Response,
MessageTask: &pb.MessageTask{
Id: int64(task.Id),
MessageRecipient: pbRecipient,
MessageMediaInstance: &pb.MessageMediaInstance{
Id: int64(instance.Id),
Name: instance.Name,
},
User: task.User,
Subject: task.Subject,
Body: task.Body,
CreatedAt: int64(task.CreatedAt),
Status: int32(task.Status),
SentAt: int64(task.SentAt),
Result: nil,
},
})
}
return &pb.ListMessageTaskLogsResponse{MessageTaskLogs: pbLogs}, nil
}

View File

@@ -1,233 +0,0 @@
package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"google.golang.org/grpc/metadata"
)
type MonitorNodeService struct {
BaseService
}
// CreateMonitorNode 创建监控节点
func (this *MonitorNodeService) CreateMonitorNode(ctx context.Context, req *pb.CreateMonitorNodeRequest) (*pb.CreateMonitorNodeResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
nodeId, err := models.SharedMonitorNodeDAO.CreateMonitorNode(tx, req.Name, req.Description, req.IsOn)
if err != nil {
return nil, err
}
return &pb.CreateMonitorNodeResponse{MonitorNodeId: nodeId}, nil
}
// UpdateMonitorNode 修改监控节点
func (this *MonitorNodeService) UpdateMonitorNode(ctx context.Context, req *pb.UpdateMonitorNodeRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMonitorNodeDAO.UpdateMonitorNode(tx, req.MonitorNodeId, req.Name, req.Description, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteMonitorNode 删除监控节点
func (this *MonitorNodeService) DeleteMonitorNode(ctx context.Context, req *pb.DeleteMonitorNodeRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedMonitorNodeDAO.DisableMonitorNode(tx, req.MonitorNodeId)
if err != nil {
return nil, err
}
return this.Success()
}
// FindAllEnabledMonitorNodes 列出所有可用监控节点
func (this *MonitorNodeService) FindAllEnabledMonitorNodes(ctx context.Context, req *pb.FindAllEnabledMonitorNodesRequest) (*pb.FindAllEnabledMonitorNodesResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
nodes, err := models.SharedMonitorNodeDAO.FindAllEnabledMonitorNodes(tx)
if err != nil {
return nil, err
}
result := []*pb.MonitorNode{}
for _, node := range nodes {
result = append(result, &pb.MonitorNode{
Id: int64(node.Id),
IsOn: node.IsOn,
UniqueId: node.UniqueId,
Secret: node.Secret,
Name: node.Name,
Description: node.Description,
})
}
return &pb.FindAllEnabledMonitorNodesResponse{MonitorNodes: result}, nil
}
// CountAllEnabledMonitorNodes 计算监控节点数量
func (this *MonitorNodeService) CountAllEnabledMonitorNodes(ctx context.Context, req *pb.CountAllEnabledMonitorNodesRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedMonitorNodeDAO.CountAllEnabledMonitorNodes(tx)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListEnabledMonitorNodes 列出单页的监控节点
func (this *MonitorNodeService) ListEnabledMonitorNodes(ctx context.Context, req *pb.ListEnabledMonitorNodesRequest) (*pb.ListEnabledMonitorNodesResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
nodes, err := models.SharedMonitorNodeDAO.ListEnabledMonitorNodes(tx, req.Offset, req.Size)
if err != nil {
return nil, err
}
result := []*pb.MonitorNode{}
for _, node := range nodes {
result = append(result, &pb.MonitorNode{
Id: int64(node.Id),
IsOn: node.IsOn,
UniqueId: node.UniqueId,
Secret: node.Secret,
Name: node.Name,
Description: node.Description,
StatusJSON: node.Status,
})
}
return &pb.ListEnabledMonitorNodesResponse{MonitorNodes: result}, nil
}
// FindEnabledMonitorNode 根据ID查找节点
func (this *MonitorNodeService) FindEnabledMonitorNode(ctx context.Context, req *pb.FindEnabledMonitorNodeRequest) (*pb.FindEnabledMonitorNodeResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
node, err := models.SharedMonitorNodeDAO.FindEnabledMonitorNode(tx, req.MonitorNodeId)
if err != nil {
return nil, err
}
if node == nil {
return &pb.FindEnabledMonitorNodeResponse{MonitorNode: nil}, nil
}
result := &pb.MonitorNode{
Id: int64(node.Id),
IsOn: node.IsOn,
UniqueId: node.UniqueId,
Secret: node.Secret,
Name: node.Name,
Description: node.Description,
}
return &pb.FindEnabledMonitorNodeResponse{MonitorNode: result}, nil
}
// FindCurrentMonitorNode 获取当前监控节点的版本
func (this *MonitorNodeService) FindCurrentMonitorNode(ctx context.Context, req *pb.FindCurrentMonitorNodeRequest) (*pb.FindCurrentMonitorNodeResponse, error) {
_, err := this.ValidateMonitorNode(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, errors.New("context: need 'nodeId'")
}
nodeIds := md.Get("nodeid")
if len(nodeIds) == 0 {
return nil, errors.New("invalid 'nodeId'")
}
nodeId := nodeIds[0]
node, err := models.SharedMonitorNodeDAO.FindEnabledMonitorNodeWithUniqueId(tx, nodeId)
if err != nil {
return nil, err
}
if node == nil {
return &pb.FindCurrentMonitorNodeResponse{MonitorNode: nil}, nil
}
result := &pb.MonitorNode{
Id: int64(node.Id),
IsOn: node.IsOn,
UniqueId: node.UniqueId,
Secret: node.Secret,
Name: node.Name,
Description: node.Description,
}
return &pb.FindCurrentMonitorNodeResponse{MonitorNode: result}, nil
}
// UpdateMonitorNodeStatus 更新节点状态
func (this *MonitorNodeService) UpdateMonitorNodeStatus(ctx context.Context, req *pb.UpdateMonitorNodeStatusRequest) (*pb.RPCSuccess, error) {
// 校验节点
_, nodeId, err := this.ValidateNodeId(ctx, rpcutils.UserTypeMonitor)
if err != nil {
return nil, err
}
if req.MonitorNodeId > 0 {
nodeId = req.MonitorNodeId
}
if nodeId <= 0 {
return nil, errors.New("'nodeId' should be greater than 0")
}
var tx = this.NullTx()
err = models.SharedMonitorNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -2066,7 +2066,7 @@ func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.
}
// thresholds
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, 0, req.NodeId)
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, int64(node.ClusterId), req.NodeId)
if err != nil {
return nil, err
}

View File

@@ -80,7 +80,7 @@ func (this *NodeClusterService) CreateNodeCluster(ctx context.Context, req *pb.C
req.DnsTTL = 0
}
clusterId, err = models.SharedNodeClusterDAO.CreateCluster(tx, adminId, req.Name, req.NodeGrantId, req.InstallDir, req.DnsDomainId, req.DnsName, req.DnsTTL, req.HttpCachePolicyId, req.HttpFirewallPolicyId, systemServices, serverGlobalConfig, req.AutoInstallNftables)
clusterId, err = models.SharedNodeClusterDAO.CreateCluster(tx, adminId, req.Name, req.NodeGrantId, req.InstallDir, req.DnsDomainId, req.DnsName, req.DnsTTL, req.HttpCachePolicyId, req.HttpFirewallPolicyId, systemServices, serverGlobalConfig, req.AutoInstallNftables, req.AutoSystemTuning)
if err != nil {
return err
}
@@ -127,7 +127,7 @@ func (this *NodeClusterService) UpdateNodeCluster(ctx context.Context, req *pb.U
}
}
err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.AutoOpenPorts, clockConfig, req.AutoRemoteStart, req.AutoInstallNftables, sshParams)
err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.AutoOpenPorts, clockConfig, req.AutoRemoteStart, req.AutoInstallNftables, sshParams, req.AutoSystemTuning)
if err != nil {
return nil, err
}
@@ -233,6 +233,7 @@ func (this *NodeClusterService) FindEnabledNodeCluster(ctx context.Context, req
ClockJSON: cluster.Clock,
AutoRemoteStart: cluster.AutoRemoteStart,
AutoInstallNftables: cluster.AutoInstallNftables,
AutoSystemTuning: cluster.AutoSystemTuning,
}}, nil
}
@@ -963,15 +964,21 @@ func (this *NodeClusterService) FindFreePortInNodeCluster(ctx context.Context, r
}
var tx = this.NullTx()
globalConfig, err := models.SharedSysSettingDAO.ReadGlobalConfig(tx)
// 检查端口
globalServerConfig, err := models.SharedNodeClusterDAO.FindClusterGlobalServerConfig(tx, req.NodeClusterId)
if err != nil {
return nil, err
}
// 检查端口
portMin := globalConfig.TCPAll.PortRangeMin
portMax := globalConfig.TCPAll.PortRangeMax
denyPorts := globalConfig.TCPAll.DenyPorts
var portMin, portMax int
var denyPorts []int
if globalServerConfig != nil {
portMin = globalServerConfig.TCPAll.PortRangeMin
portMax = globalServerConfig.TCPAll.PortRangeMax
denyPorts = globalServerConfig.TCPAll.DenyPorts
}
if portMin == 0 && portMax == 0 {
portMin = 10_000
@@ -1190,6 +1197,9 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
result.Http3IsOn = http3Policy.IsOn
}
// 网络安全策略
result.HasNetworkSecurityPolicy = cluster.HasNetworkSecurityPolicy()
return result, nil
}

View File

@@ -11,3 +11,13 @@ import (
func (this *NodeClusterService) FindNodeClusterHTTP3Policy(ctx context.Context, req *pb.FindNodeClusterHTTP3PolicyRequest) (*pb.FindNodeClusterHTTP3PolicyResponse, error) {
return nil, this.NotImplementedYet()
}
// FindNodeClusterNetworkSecurityPolicy 获取集群的网络安全策略
func (this *NodeClusterService) FindNodeClusterNetworkSecurityPolicy(ctx context.Context, req *pb.FindNodeClusterNetworkSecurityPolicyRequest) (*pb.FindNodeClusterNetworkSecurityPolicyResponse, error) {
return nil, this.NotImplementedYet()
}
// UpdateNodeClusterNetworkSecurityPolicy 修改集群的网络安全策略
func (this *NodeClusterService) UpdateNodeClusterNetworkSecurityPolicy(ctx context.Context, req *pb.UpdateNodeClusterNetworkSecurityPolicyRequest) (*pb.RPCSuccess, error) {
return nil, this.NotImplementedYet()
}

View File

@@ -52,3 +52,8 @@ func (this *NodeService) CopyNodeActionsToNodeCluster(ctx context.Context, req *
func (this *NodeService) FindNodeTOAConfig(ctx context.Context, req *pb.FindNodeTOAConfigRequest) (*pb.FindNodeTOAConfigResponse, error) {
return nil, this.NotImplementedYet()
}
// FindNodeNetworkSecurityPolicy 查找节点的网络安全策略
func (this *NodeService) FindNodeNetworkSecurityPolicy(ctx context.Context, req *pb.FindNodeNetworkSecurityPolicyRequest) (*pb.FindNodeNetworkSecurityPolicyResponse, error) {
return nil, this.NotImplementedYet()
}

View File

@@ -216,7 +216,7 @@ func (this *ReverseProxyService) UpdateReverseProxy(ctx context.Context, req *pb
}
}
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects)
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects, req.Retry50X, req.Retry40X)
if err != nil {
return nil, err
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
@@ -117,12 +118,12 @@ func (this *ServerService) CreateServer(ctx context.Context, req *pb.CreateServe
var auditingServerNamesJSON = []byte("[]")
if userId > 0 {
// 如果域名不为空的时候需要审核
if len(serverNamesJSON) > 0 && string(serverNamesJSON) != "[]" {
globalConfig, err := models.SharedSysSettingDAO.ReadGlobalConfig(tx)
if len(serverNamesJSON) > 0 && string(serverNamesJSON) != "[]" && req.NodeClusterId > 0 {
globalServerConfig, err := models.SharedNodeClusterDAO.FindClusterGlobalServerConfig(tx, req.NodeClusterId)
if err != nil {
return nil, err
}
if globalConfig != nil && globalConfig.HTTPAll.DomainAuditingIsOn {
if globalServerConfig != nil && globalServerConfig.HTTPAll.DomainAuditingIsOn {
isAuditing = true
serverNamesJSON = []byte("[]")
auditingServerNamesJSON = req.ServerNamesJSON
@@ -147,7 +148,7 @@ func (this *ServerService) CreateServer(ctx context.Context, req *pb.CreateServe
}
// 套餐
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return nil, err
}
@@ -258,11 +259,12 @@ func (this *ServerService) CreateBasicHTTPServer(ctx context.Context, req *pb.Cr
if userId > 0 {
// 如果域名不为空的时候需要审核
if len(serverNamesJSON) > 0 && string(serverNamesJSON) != "[]" {
globalConfig, err := models.SharedSysSettingDAO.ReadGlobalConfig(tx)
globalServerConfig, err := models.SharedNodeClusterDAO.FindClusterGlobalServerConfig(tx, req.NodeClusterId)
if err != nil {
return nil, err
}
if globalConfig != nil && globalConfig.HTTPAll.DomainAuditingIsOn {
if globalServerConfig != nil && globalServerConfig.HTTPAll.DomainAuditingIsOn {
isAuditing = true
serverNamesJSON = []byte("[]")
auditingServerNamesJSON = serverNamesJSON
@@ -1076,6 +1078,12 @@ func (this *ServerService) UpdateServerNames(ctx context.Context, req *pb.Update
}
}
// 套餐额度限制
err = models.SharedServerDAO.CheckServerPlanQuota(tx, req.ServerId, len(serverconfigs.PlainServerNames(serverNameConfigs)))
if err != nil {
return nil, err
}
// 检查用户
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
@@ -1084,22 +1092,31 @@ func (this *ServerService) UpdateServerNames(ctx context.Context, req *pb.Update
}
// 是否需要审核
globalConfig, err := models.SharedSysSettingDAO.ReadGlobalConfig(tx)
clusterId, err := models.SharedServerDAO.FindServerClusterId(tx, req.ServerId)
if err != nil {
return nil, err
}
if globalConfig != nil && globalConfig.HTTPAll.DomainAuditingIsOn {
err = models.SharedServerDAO.UpdateAuditingServerNames(tx, req.ServerId, true, req.ServerNamesJSON)
if clusterId > 0 {
globalServerConfig, err := models.SharedNodeClusterDAO.FindClusterGlobalServerConfig(tx, clusterId)
if err != nil {
return nil, err
}
if globalServerConfig != nil && globalServerConfig.HTTPAll.DomainAuditingIsOn {
err = models.SharedServerDAO.UpdateAuditingServerNames(tx, req.ServerId, true, req.ServerNamesJSON)
if err != nil {
return nil, err
}
// 发送审核通知
err = models.SharedMessageDAO.CreateMessage(tx, 0, 0, models.MessageTypeServerNamesRequireAuditing, models.MessageLevelWarning, "有新的网站域名需要审核", "有新的网站域名需要审核", maps.Map{
"serverId": req.ServerId,
}.AsJSON())
// 发送审核通知
err = models.SharedMessageDAO.CreateMessage(tx, 0, 0, models.MessageTypeServerNamesRequireAuditing, models.MessageLevelWarning, "有新的网站域名需要审核", "有新的网站域名需要审核", maps.Map{
"serverId": req.ServerId,
}.AsJSON())
if err != nil {
return nil, err
}
return this.Success()
return this.Success()
}
}
}
@@ -1278,7 +1295,7 @@ func (this *ServerService) CountAllEnabledServersMatch(ctx context.Context, req
var tx = this.NullTx()
count, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, types.Int8(req.AuditingFlag), utils.SplitStrings(req.ProtocolFamily, ","))
count, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, types.Int8(req.AuditingFlag), utils.SplitStrings(req.ProtocolFamily, ","), req.UserPlanId)
if err != nil {
return nil, err
}
@@ -2019,6 +2036,52 @@ func (this *ServerService) FindAllEnabledServerNamesWithUserId(ctx context.Conte
return &pb.FindAllEnabledServerNamesWithUserIdResponse{ServerNames: serverNames}, nil
}
// CountAllServerNamesWithUserId 计算一个用户下的所有域名数量
func (this *ServerService) CountAllServerNamesWithUserId(ctx context.Context, req *pb.CountAllServerNamesWithUserIdRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
count, err := models.SharedServerDAO.CountAllServerNamesWithUserId(tx, req.UserId, req.UserPlanId)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// CountServerNames 计算某个网站下的域名数量
func (this *ServerService) CountServerNames(ctx context.Context, req *pb.CountServerNamesRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if req.ServerId <= 0 {
return nil, errors.New("invalid 'serverId'")
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
if err != nil {
return nil, err
}
}
count, err := models.SharedServerDAO.CountServerNames(tx, req.ServerId)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// FindAllUserServers 查找一个用户下的所有服务
func (this *ServerService) FindAllUserServers(ctx context.Context, req *pb.FindAllUserServersRequest) (*pb.FindAllUserServersResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
@@ -2051,6 +2114,26 @@ func (this *ServerService) FindAllUserServers(ctx context.Context, req *pb.FindA
}, nil
}
// CountAllUserServers 计算一个用户下的所有网站数量
func (this *ServerService) CountAllUserServers(ctx context.Context, req *pb.CountAllUserServersRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, nil, req.UserPlanId)
if err != nil {
return nil, err
}
return this.SuccessCount(countServers)
}
// ComposeAllUserServersConfig 查找某个用户下的服务配置
func (this *ServerService) ComposeAllUserServersConfig(ctx context.Context, req *pb.ComposeAllUserServersConfigRequest) (*pb.ComposeAllUserServersConfigResponse, error) {
_, err := this.ValidateNode(ctx)
@@ -2644,7 +2727,7 @@ func (this *ServerService) UpdateServerUserPlan(ctx context.Context, req *pb.Upd
}
if req.UserPlanId > 0 {
userId, err := models.SharedServerDAO.FindServerUserId(tx, req.ServerId)
userId, err = models.SharedServerDAO.FindServerUserId(tx, req.ServerId)
if err != nil {
return nil, err
}
@@ -2662,14 +2745,47 @@ func (this *ServerService) UpdateServerUserPlan(ctx context.Context, req *pb.Upd
if int64(userPlan.UserId) != userId {
return nil, errors.New("can not find user plan with id '" + types.String(req.UserPlanId) + "'")
}
if userPlan.IsExpired() {
return nil, fmt.Errorf("the user plan %q has been expired", types.String(req.UserPlanId))
}
// 检查是否已经被别的服务所使用
serverId, err := models.SharedServerDAO.FindEnabledServerIdWithUserPlanId(tx, req.UserPlanId)
// 检查限制
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return nil, err
}
if serverId > 0 && serverId != req.ServerId {
return nil, errors.New("the user plan is used by other server")
if plan == nil {
return nil, errors.New("can not find plan with id '" + types.String(userPlan.PlanId) + "'")
}
if plan.TotalServers > 0 {
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", userId, 0, configutils.BoolStateAll, nil, req.UserPlanId)
if err != nil {
return nil, err
}
if countServers+1 > int64(plan.TotalServers) {
return nil, errors.New("total servers over quota")
}
}
countServerNames, err := models.SharedServerDAO.CountServerNames(tx, req.ServerId)
if err != nil {
return nil, err
}
if plan.TotalServerNamesPerServer > 0 {
if countServerNames > int64(plan.TotalServerNamesPerServer) {
return nil, errors.New("total server names per server over quota")
}
}
totalServerNames, err := models.SharedServerDAO.CountAllServerNamesWithUserId(tx, userId, req.UserPlanId)
if err != nil {
return nil, err
}
if plan.TotalServerNames > 0 {
if totalServerNames+countServerNames > int64(plan.TotalServerNames) {
return nil, errors.New("total server names over quota")
}
}
}
@@ -2714,7 +2830,7 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
return &pb.FindServerUserPlanResponse{UserPlan: nil}, nil
}
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return nil, err
}
@@ -2732,11 +2848,14 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
DayTo: userPlan.DayTo,
User: nil,
Plan: &pb.Plan{
Id: int64(plan.Id),
Name: plan.Name,
PriceType: plan.PriceType,
TrafficPriceJSON: plan.TrafficPrice,
TrafficLimitJSON: plan.TrafficLimit,
Id: int64(plan.Id),
Name: plan.Name,
PriceType: plan.PriceType,
TrafficPriceJSON: plan.TrafficPrice,
TrafficLimitJSON: plan.TrafficLimit,
TotalServers: types.Int32(plan.TotalServers),
TotalServerNames: types.Int32(plan.TotalServerNames),
TotalServerNamesPerServer: types.Int32(plan.TotalServerNamesPerServer),
},
},
}, nil
@@ -2878,7 +2997,7 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
}
}
}
err = models.SharedServerDAO.CopyServerConfigToServers(tx, req.ServerId, req.TargetServerIds, req.ConfigCode)
err = models.SharedServerDAO.CopyServerConfigToServers(tx, req.ServerId, req.TargetServerIds, req.ConfigCode, req.WafCopyRegions)
if err != nil {
return nil, err
}
@@ -2895,7 +3014,7 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
}
}
}
err = models.SharedServerDAO.CopyServerConfigToGroups(tx, req.ServerId, req.TargetServerGroupIds, req.ConfigCode)
err = models.SharedServerDAO.CopyServerConfigToGroups(tx, req.ServerId, req.TargetServerGroupIds, req.ConfigCode, req.WafCopyRegions)
if err != nil {
return nil, err
}
@@ -2907,7 +3026,7 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
if req.TargetClusterId <= 0 {
return this.Success()
}
err = models.SharedServerDAO.CopyServerConfigToCluster(tx, req.ServerId, req.TargetClusterId, req.ConfigCode)
err = models.SharedServerDAO.CopyServerConfigToCluster(tx, req.ServerId, req.TargetClusterId, req.ConfigCode, req.WafCopyRegions)
if err != nil {
return nil, err
}
@@ -2926,7 +3045,7 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
// 只能同步到自己的网站
req.TargetUserId = userId
}
err = models.SharedServerDAO.CopyServerConfigToUser(tx, req.ServerId, req.TargetUserId, req.ConfigCode)
err = models.SharedServerDAO.CopyServerConfigToUser(tx, req.ServerId, req.TargetUserId, req.ConfigCode, req.WafCopyRegions)
if err != nil {
return nil, err
}
@@ -2934,3 +3053,43 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
return this.Success()
}
// FindServerAuditingPrompt 获取域名审核时的提示文字
func (this *ServerService) FindServerAuditingPrompt(ctx context.Context, req *pb.FindServerAuditingPromptRequest) (*pb.FindServerAuditingPromptResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
if err != nil {
return nil, err
}
}
clusterId, err := models.SharedServerDAO.FindServerClusterId(tx, req.ServerId)
if err != nil {
return nil, err
}
if clusterId <= 0 {
return &pb.FindServerAuditingPromptResponse{
PromptText: "",
}, nil
}
globalServerConfig, err := models.SharedNodeClusterDAO.FindClusterGlobalServerConfig(tx, clusterId)
if err != nil {
return nil, err
}
if globalServerConfig != nil {
return &pb.FindServerAuditingPromptResponse{
PromptText: globalServerConfig.HTTPAll.DomainAuditingPrompt,
}, nil
}
return &pb.FindServerAuditingPromptResponse{
PromptText: "",
}, nil
}

View File

@@ -63,17 +63,31 @@ func init() {
}
for _, stat := range m {
// 更新服务的带宽峰值
// 更新网站的带宽峰值
if stat.ServerId > 0 {
err = models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
// 更新带宽统计
err = models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.UserPlanId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
}
// 更新网站的bandwidth字段方便快速排序
err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes, stat.CountRequests, stat.CountAttackRequests)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error())
}
// 套餐统计
if stat.UserPlanId > 0 {
// 总体统计
err = models.SharedUserPlanStatDAO.IncreaseUserPlanStat(tx, stat.UserPlanId, stat.TotalBytes, stat.CountRequests)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "IncreaseUserPlanStat: "+err.Error())
}
// 分时统计
err = models.SharedUserPlanBandwidthStatDAO.UpdateUserPlanBandwidth(tx, stat.UserId, stat.UserPlanId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
}
}
// 更新用户的带宽峰值
@@ -147,6 +161,7 @@ func (this *ServerBandwidthStatService) UploadServerBandwidthStats(ctx context.C
CountRequests: stat.CountRequests,
CountCachedRequests: stat.CountCachedRequests,
CountAttackRequests: stat.CountAttackRequests,
UserPlanId: stat.UserPlanId,
}
}
serverBandwidthStatsLocker.Unlock()

Some files were not shown because too many files have changed in this diff Show More