Compare commits

..

33 Commits

Author SHA1 Message Date
刘祥超
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
76 changed files with 14542 additions and 2513 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", "autoSystemTuning" ]

View File

@@ -1,12 +1,14 @@
package teaconst
const (
Version = "1.2.8"
Version = "1.2.10"
ProductName = "Edge API"
ProcessName = "edge-api"
ProductNameZH = "Edge"
GlobalProductName = "GoEdge"
Role = "api"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
@@ -18,7 +20,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "1.2.8"
NodeVersion = "1.2.10"
// 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

@@ -461,6 +461,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 +614,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) {

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

@@ -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" // 节点健康检查失败

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)

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

@@ -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").
Find()
if err != nil || cluster == nil {
return nil, err

View File

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

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"
@@ -1057,30 +1057,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{}
@@ -1242,6 +1218,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// 自动安装nftables
if clusterIndex == 0 {
config.AutoInstallNftables = nodeCluster.AutoInstallNftables
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
}
clusterIndex++
@@ -2128,6 +2105,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

@@ -8,6 +8,7 @@ import (
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"strings"
"time"
)
@@ -19,6 +20,7 @@ const (
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
@@ -265,6 +267,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 +293,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

@@ -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,7 @@ 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
var schedulingConfig = &serverconfigs.SchedulingConfig{}
if IsNotNull(reverseProxy.Scheduling) {
@@ -218,6 +219,7 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
op.AdminId = adminId
op.UserId = userId
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
op.Retry50X = true
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
@@ -425,7 +427,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
maxConns int32,
maxIdleConns int32,
proxyProtocolJSON []byte,
followRedirects bool) error {
followRedirects bool,
retry50X bool) error {
if reverseProxyId <= 0 {
return errors.New("invalid reverseProxyId")
}
@@ -490,6 +493,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
op.ProxyProtocol = proxyProtocolJSON
}
op.Retry50X = retry50X
err = this.Save(tx, op)
if err != nil {
return err

View File

@@ -2,6 +2,34 @@ 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重试
)
// ReverseProxy 反向代理配置
type ReverseProxy struct {
Id uint32 `field:"id"` // ID
@@ -28,33 +56,35 @@ type ReverseProxy struct {
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
Retry50X bool `field:"retry50X"` // 启用50X重试
}
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重试
}
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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

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)
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()

View File

@@ -191,7 +191,7 @@ func (this *SSLCertService) CountSSLCerts(ctx context.Context, req *pb.CountSSLC
return nil, errors.New("invalid user")
}
count, err := models.SharedSSLCertDAO.CountCerts(tx, req.IsCA, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, userId, req.Domains)
count, err := models.SharedSSLCertDAO.CountCerts(tx, req.IsCA, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, userId, req.Domains, req.UserOnly)
if err != nil {
return nil, err
}
@@ -215,7 +215,7 @@ func (this *SSLCertService) ListSSLCerts(ctx context.Context, req *pb.ListSSLCer
var tx = this.NullTx()
certIds, err := models.SharedSSLCertDAO.ListCertIds(tx, req.IsCA, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, userId, req.Domains, req.Offset, req.Size)
certIds, err := models.SharedSSLCertDAO.ListCertIds(tx, req.IsCA, req.IsAvailable, req.IsExpired, int64(req.ExpiringDays), req.Keyword, userId, req.Domains, req.UserOnly, req.Offset, req.Size)
if err != nil {
return nil, err
}
@@ -368,3 +368,40 @@ func (this *SSLCertService) ListUpdatedSSLCertOCSP(ctx context.Context, req *pb.
SslCertOCSP: result,
}, nil
}
// FindSSLCertUser 查找证书所属用户
func (this *SSLCertService) FindSSLCertUser(ctx context.Context, req *pb.FindSSLCertUserRequest) (*pb.FindSSLCertUserResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
userId, err := models.SharedSSLCertDAO.FindCertUserId(tx, req.SslCertId)
if err != nil {
return nil, err
}
if userId <= 0 {
return &pb.FindSSLCertUserResponse{User: nil}, nil
}
user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, userId)
if err != nil {
return nil, err
}
if user == nil {
return &pb.FindSSLCertUserResponse{
User: &pb.User{
Id: userId,
},
}, nil
}
return &pb.FindSSLCertUserResponse{
User: &pb.User{
Id: userId,
Username: user.Username,
Fullname: user.Fullname,
},
}, nil
}

View File

@@ -14,12 +14,6 @@ type SysLockerService struct {
// SysLockerLock 获得锁
func (this *SysLockerService) SysLockerLock(ctx context.Context, req *pb.SysLockerLockRequest) (*pb.SysLockerLockResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
_, err = this.ValidateMonitorNode(ctx)
if err != nil {
return nil, err
}
}
key := req.Key
if userId > 0 {
@@ -44,12 +38,6 @@ func (this *SysLockerService) SysLockerLock(ctx context.Context, req *pb.SysLock
// SysLockerUnlock 释放锁
func (this *SysLockerService) SysLockerUnlock(ctx context.Context, req *pb.SysLockerUnlockRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
_, err = this.ValidateMonitorNode(ctx)
if err != nil {
return nil, err
}
}
key := req.Key
if userId > 0 {

View File

@@ -412,7 +412,7 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
}
// 网站数量
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, []string{})
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, []string{}, 0)
if err != nil {
return nil, err
}

View File

@@ -14,7 +14,6 @@ const (
UserTypeProvider = "provider"
UserTypeNode = "node"
UserTypeCluster = "cluster"
UserTypeMonitor = "monitor"
UserTypeStat = "stat"
UserTypeDNS = "dns"
UserTypeLog = "log"

File diff suppressed because it is too large Load Diff

View File

@@ -60,6 +60,11 @@ var recordsTables = []*SQLRecordsTable{
UniqueFields: []string{"agentId", "ip"},
IgnoreId: true,
},
{
TableName: "edgeMessageMedias",
UniqueFields: []string{"type"},
IgnoreId: true,
},
}
type sqlItem struct {

View File

@@ -95,6 +95,12 @@ var upgradeFuncs = []*upgradeVersion{
{
"1.2.1", upgradeV1_2_1,
},
{
"1.2.9", upgradeV1_2_9,
},
{
"1.2.10", upgradeV1_2_10,
},
}
// UpgradeSQLData 升级SQL数据
@@ -746,3 +752,67 @@ func upgradeV1_2_1(db *dbs.DB) error {
}
return nil
}
// 1.2.10
func upgradeV1_2_10(db *dbs.DB) error {
{
type OldGlobalConfig struct {
// HTTP & HTTPS相关配置
HTTPAll struct {
DomainAuditingIsOn bool `yaml:"domainAuditingIsOn" json:"domainAuditingIsOn"` // 域名是否需要审核
DomainAuditingPrompt string `yaml:"domainAuditingPrompt" json:"domainAuditingPrompt"` // 域名审核的提示
} `yaml:"httpAll" json:"httpAll"`
TCPAll struct {
PortRangeMin int `yaml:"portRangeMin" json:"portRangeMin"` // 最小端口
PortRangeMax int `yaml:"portRangeMax" json:"portRangeMax"` // 最大端口
DenyPorts []int `yaml:"denyPorts" json:"denyPorts"` // 禁止使用的端口
} `yaml:"tcpAll" json:"tcpAll"`
}
globalConfigValue, err := db.FindCol(0, "SELECT value FROM edgeSysSettings WHERE code='serverGlobalConfig'")
if err != nil {
return err
}
var globalConfigString = types.String(globalConfigValue)
if len(globalConfigString) > 0 {
var oldGlobalConfig = &OldGlobalConfig{}
err = json.Unmarshal([]byte(globalConfigString), oldGlobalConfig)
if err == nil { // we ignore error
ones, _, err := db.FindOnes("SELECT id,globalServerConfig FROM edgeNodeClusters")
if err != nil {
return err
}
for _, one := range ones {
var id = one.GetInt64("id")
var globalServerConfigData = []byte(one.GetString("globalServerConfig"))
if len(globalServerConfigData) > 32 {
var globalServerConfig = &serverconfigs.GlobalServerConfig{}
err = json.Unmarshal(globalServerConfigData, globalServerConfig)
if err != nil {
return err
}
globalServerConfig.HTTPAll.DomainAuditingIsOn = oldGlobalConfig.HTTPAll.DomainAuditingIsOn
globalServerConfig.HTTPAll.DomainAuditingPrompt = oldGlobalConfig.HTTPAll.DomainAuditingPrompt
globalServerConfig.TCPAll.DenyPorts = oldGlobalConfig.TCPAll.DenyPorts
globalServerConfig.TCPAll.PortRangeMin = oldGlobalConfig.TCPAll.PortRangeMin
globalServerConfig.TCPAll.PortRangeMax = oldGlobalConfig.TCPAll.PortRangeMax
globalServerConfigJSON, err := json.Marshal(globalServerConfig)
if err != nil {
return err
}
_, err = db.Exec("UPDATE edgeNodeClusters SET globalServerConfig=? WHERE id=?", globalServerConfigJSON, id)
if err != nil {
return err
}
}
}
}
}
}
return nil
}

View File

@@ -213,3 +213,16 @@ func upgradeV0_5_8(db *dbs.DB) error {
return nil
}
// v1.2.9
func upgradeV1_2_9(db *dbs.DB) error {
// 升级WAF规则
{
_, err := db.Exec("UPDATE edgeHTTPFirewallRules SET value=? WHERE value=? AND param='${userAgent}'", "python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php\\b|rust", "python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php|rust")
if err != nil {
return err
}
}
return nil
}

View File

@@ -271,4 +271,21 @@ func TestUpgradeSQLData_v1_2_1(t *testing.T) {
t.Log("ok")
}
func TestUpgradeSQLData_v1_2_10(t *testing.T) {
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
Driver: "mysql",
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
Prefix: "edge",
})
if err != nil {
t.Fatal(err)
}
defer func() {
_ = db.Close()
}()
err = upgradeV1_2_10(db)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -144,7 +144,7 @@ func (this *NodeMonitorTask) MonitorCluster(cluster *models.NodeCluster) error {
this.notifiedMap[nodeId] = time.Now().Unix()
var subject = "节点\"" + node.Name + "\"已处于离线状态"
var msg = "集群'" + cluster.Name + "'节点\"" + node.Name + "\"已处于离线状态,请检查节点是否异常"
var msg = "集群 \"" + cluster.Name + "\" 节点 \"" + node.Name + "\" 已处于离线状态,请检查节点是否异常"
err = models.SharedMessageDAO.CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, clusterId, int64(node.Id), models.MessageTypeNodeInactive, models.LevelError, subject, msg, nil, false)
if err != nil {
return err