Compare commits

...

24 Commits

Author SHA1 Message Date
刘祥超
22d15bcb27 华为云DNS线路增加一组"运营商_地区“线路 2023-12-25 09:05:06 +08:00
刘祥超
361fb9b868 升级程序中的1.3.1.x改为1.3.2 2023-12-24 17:40:40 +08:00
刘祥超
2d675f4281 源码编译版本增加节点数限制 2023-12-24 11:28:41 +08:00
刘祥超
e19bbdf891 版本号修改为1.3.2 2023-12-24 11:14:39 +08:00
刘祥超
d48c0a2328 增加列出IP名单中的IP ID列表的API 2023-12-24 10:51:29 +08:00
刘祥超
a70b20cf13 增加请求脚本审核机制 2023-12-23 20:56:11 +08:00
刘祥超
eb83017ed4 修复一处编译错误 2023-12-22 16:46:37 +08:00
刘祥超
98ba31174b 套餐增加简介信息 2023-12-21 15:09:50 +08:00
刘祥超
aa28e84507 增加若干功能代号 2023-12-20 17:34:54 +08:00
刘祥超
da8fe918fe 更新SQL 2023-12-20 15:54:36 +08:00
刘祥超
2b26bed97c 增加若干API 2023-12-20 15:08:05 +08:00
刘祥超
5e50518bd9 限制ACME错误消息长度 2023-12-19 20:05:34 +08:00
刘祥超
e49db916f8 套餐增加Websocket连接数限制 2023-12-19 14:56:44 +08:00
刘祥超
16083fd0d7 增加多个台湾地区区县地址 2023-12-18 09:43:49 +08:00
刘祥超
e0e2729fef 版本号修改为1.3.1.2 2023-12-18 08:51:04 +08:00
刘祥超
9b95042936 缓存设置中可以设置缓存主域名,用来复用多域名下的缓存 2023-12-13 18:34:57 +08:00
刘祥超
44d45c53a1 增加保存管理员语言选择的API 2023-12-12 22:40:06 +08:00
刘祥超
c5fb340eb7 自动升级WAF策略中SQL注入检测和XSS注入检测 2023-12-12 17:15:21 +08:00
刘祥超
cbb61d2f0e 读取用户信息时同时返回语言设置 2023-12-12 11:49:05 +08:00
刘祥超
a143714370 WebP策略变化时只更新相关配置 2023-12-11 11:08:19 +08:00
刘祥超
0e1a98c5d8 将部分MB、GB...改成MiB、GiB... 2023-12-03 11:32:09 +08:00
刘祥超
707a9f8caf 优化代码 2023-11-29 16:58:11 +08:00
刘祥超
da391f565b 创建集群时默认生成子域名 2023-11-27 11:28:31 +08:00
刘祥超
78f396129f 阿里云线路显示完整的线路名称 2023-11-26 20:16:13 +08:00
41 changed files with 4382 additions and 374 deletions

View File

@@ -1,7 +1,7 @@
package teaconst
const (
Version = "1.3.1"
Version = "1.3.2"
ProductName = "Edge API"
ProcessName = "edge-api"
@@ -20,7 +20,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "1.3.1"
NodeVersion = "1.3.2"
// SQLVersion SQL版本号
SQLVersion = "11"

View File

@@ -0,0 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package teaconst
const (
// DefaultMaxNodes 节点数限制
DefaultMaxNodes int32 = 50
)

View File

@@ -1,6 +1,7 @@
package acme
import (
"github.com/TeaOSLab/EdgeAPI/internal/utils"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -31,7 +32,7 @@ func init() {
func (this *ACMETaskLogDAO) CreateACMETaskLog(tx *dbs.Tx, taskId int64, isOk bool, errMsg string) error {
var op = NewACMETaskLogOperator()
op.TaskId = taskId
op.Error = errMsg
op.Error = utils.LimitString(errMsg, 1024)
op.IsOk = isOk
err := this.Save(tx, op)
return err

View File

@@ -260,7 +260,7 @@ func (this *AdminDAO) FindAllAdminModules(tx *dbs.Tx) (result []*Admin, err erro
_, err = this.Query(tx).
State(AdminStateEnabled).
Attr("isOn", true).
Result("id", "modules", "isSuper", "fullname", "theme").
Result("id", "modules", "isSuper", "fullname", "theme", "lang").
Slice(&result).
FindAll()
return
@@ -313,6 +313,14 @@ func (this *AdminDAO) UpdateAdminTheme(tx *dbs.Tx, adminId int64, theme string)
UpdateQuickly()
}
// UpdateAdminLang 设置管理员语言
func (this *AdminDAO) UpdateAdminLang(tx *dbs.Tx, adminId int64, langCode string) error {
return this.Query(tx).
Pk(adminId).
Set("lang", langCode).
UpdateQuickly()
}
// CheckSuperAdmin 检查管理员是否为超级管理员
func (this *AdminDAO) CheckSuperAdmin(tx *dbs.Tx, adminId int64) (bool, error) {
if adminId <= 0 {

View File

@@ -444,6 +444,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
var config = &firewallconfigs.HTTPFirewallPolicy{}
config.Id = int64(policy.Id)
config.ServerId = int64(policy.ServerId)
config.IsOn = policy.IsOn
config.Name = policy.Name
config.Description = policy.Description
@@ -667,6 +668,19 @@ func (this *HTTPFirewallPolicyDAO) FindFirewallPolicyIdsWithServerId(tx *dbs.Tx,
return result, nil
}
// FindServerIdWithFirewallPolicyId 根据策略查找网站ID
func (this *HTTPFirewallPolicyDAO) FindServerIdWithFirewallPolicyId(tx *dbs.Tx, policyId int64) (serverId int64, err error) {
if policyId <= 0 {
return
}
serverId, err = this.Query(tx).
Pk(policyId).
Result("serverId").
FindInt64Col(0)
return
}
// NotifyUpdate 通知更新
func (this *HTTPFirewallPolicyDAO) NotifyUpdate(tx *dbs.Tx, policyId int64) error {
webIds, err := SharedHTTPWebDAO.FindAllWebIdsWithHTTPFirewallPolicyId(tx, policyId)

View File

@@ -1299,6 +1299,61 @@ func (this *HTTPWebDAO) UpdateWebRequestScripts(tx *dbs.Tx, webId int64, config
return this.NotifyUpdate(tx, webId)
}
// UpdateWebRequestScriptsAsPassed 设置请求脚本为审核通过
func (this *HTTPWebDAO) UpdateWebRequestScriptsAsPassed(tx *dbs.Tx, webId int64, codeMD5 string) error {
if webId <= 0 || len(codeMD5) == 0 {
return nil
}
configString, err := this.Query(tx).
Pk(webId).
Result("requestScripts").
FindStringCol("")
if err != nil {
return nil
}
var config = &serverconfigs.HTTPRequestScriptsConfig{}
if len(configString) == 0 {
return nil
}
err = json.Unmarshal([]byte(configString), config)
if err != nil {
return err
}
var found bool
for _, group := range config.AllGroups() {
for _, script := range group.Scripts {
if script.AuditingCodeMD5 == codeMD5 {
script.Code = script.AuditingCode
script.AuditingCode = ""
script.AuditingCodeMD5 = ""
found = true
}
}
}
if found {
configJSON, err := json.Marshal(config)
if err != nil {
return err
}
err = this.Query(tx).
Pk(webId).
Set("requestScripts", configJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
return nil
}
// FindWebRequestScripts 查找服务的脚本设置
func (this *HTTPWebDAO) FindWebRequestScripts(tx *dbs.Tx, webId int64) (*serverconfigs.HTTPRequestScriptsConfig, error) {
configString, err := this.Query(tx).

View File

@@ -582,6 +582,62 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, key
return
}
// ListAllIPItemIds 搜索所有IP Id列表
func (this *IPItemDAO) ListAllIPItemIds(tx *dbs.Tx, sourceUserId int64, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string, offset int64, size int64) (itemIds []int64, err error) {
var query = this.Query(tx)
if sourceUserId > 0 {
if listId <= 0 {
query.Where("((listId=" + types.String(firewallconfigs.GlobalListId) + " AND sourceUserId=:sourceUserId) OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
} else if listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
}
}
if len(keyword) > 0 {
if net.ParseIP(keyword) != nil { // 是一个IP地址
query.Attr("ipFrom", keyword)
} else {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
}
}
if len(ip) > 0 {
query.Attr("ipFrom", ip)
}
if listId > 0 {
query.Attr("listId", listId)
} else {
if len(listType) > 0 {
query.Where("(listId=" + types.String(firewallconfigs.GlobalListId) + " OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE state=1 AND type=:listType))")
query.Param("listType", listType)
} else {
query.Where("(listId=" + types.String(firewallconfigs.GlobalListId) + " OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE state=1))")
}
}
if unread {
query.Attr("isRead", 0)
}
if len(eventLevel) > 0 {
query.Attr("eventLevel", eventLevel)
}
result, err := query.
ResultPk().
State(IPItemStateEnabled).
Where("(expiredAt=0 OR expiredAt>:expiredAt)").
Param("expiredAt", time.Now().Unix()).
DescPk().
Offset(offset).
Size(size).
FindAll()
if err != nil {
return nil, err
}
for _, itemOne := range result {
itemIds = append(itemIds, int64(itemOne.(*IPItem).Id))
}
return
}
// UpdateItemsRead 设置所有未已读
func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx, sourceUserId int64) error {
var query = this.Query(tx).

View File

@@ -339,3 +339,16 @@ func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskT
return nil
}
// FindServerIdWithListId 查找IP名单对应的网站ID
func (this *IPListDAO) FindServerIdWithListId(tx *dbs.Tx, listId int64) (serverId int64, err error) {
if listId <= 0 {
return
}
serverId, err = this.Query(tx).
Pk(listId).
Result("serverId").
FindInt64Col(0)
return
}

View File

@@ -1043,7 +1043,7 @@ func (this *NodeClusterDAO) UpdateClusterWebPPolicy(tx *dbs.Tx, clusterId int64,
return err
}
return this.NotifyUpdate(tx, clusterId)
return this.NotifyWebPPolicyUpdate(tx, clusterId)
}
webpPolicyJSON, err := json.Marshal(webpPolicy)
@@ -1058,7 +1058,7 @@ func (this *NodeClusterDAO) UpdateClusterWebPPolicy(tx *dbs.Tx, clusterId int64,
return err
}
return this.NotifyUpdate(tx, clusterId)
return this.NotifyWebPPolicyUpdate(tx, clusterId)
}
// FindClusterWebPPolicy 查询WebP设置
@@ -1083,7 +1083,7 @@ func (this *NodeClusterDAO) FindClusterWebPPolicy(tx *dbs.Tx, clusterId int64, c
return nodeconfigs.DefaultWebPImagePolicy, nil
}
var policy = &nodeconfigs.WebPImagePolicy{}
var policy = nodeconfigs.NewWebPImagePolicy()
err = json.Unmarshal(webpJSON, policy)
if err != nil {
return nil, err
@@ -1518,6 +1518,11 @@ func (this *NodeClusterDAO) NotifyTOAUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeTOAChanged)
}
// NotifyWebPPolicyUpdate 通知WebP策略更新
func (this *NodeClusterDAO) NotifyWebPPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeWebPPolicyChanged)
}
// NotifyDNSUpdate 通知DNS更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {

View File

@@ -1151,7 +1151,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// webp
if IsNotNull(nodeCluster.Webp) {
var webpPolicy = &nodeconfigs.WebPImagePolicy{}
var webpPolicy = nodeconfigs.NewWebPImagePolicy()
err = json.Unmarshal(nodeCluster.Webp, webpPolicy)
if err != nil {
return nil, err

View File

@@ -4,7 +4,10 @@
package models
import (
"errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
)
func (this *NodeDAO) CountAllAuthorityNodes(tx *dbs.Tx) (int64, error) {
@@ -15,5 +18,18 @@ func (this *NodeDAO) CountAllAuthorityNodes(tx *dbs.Tx) (int64, error) {
}
func (this *NodeDAO) CheckNodesLimit(tx *dbs.Tx) error {
var maxNodes = teaconst.DefaultMaxNodes
// 检查节点数量
if maxNodes > 0 {
count, err := this.CountAllAuthorityNodes(tx)
if err != nil {
return err
}
if count >= int64(maxNodes) {
return errors.New("超出最大节点数限制:" + types.String(maxNodes) + ",当前已用:" + types.String(count) + "请自行修改源码修改此限制EdgeAPI/internal/const/const_community.go 或者 购买商业版本授权。")
}
}
return nil
}

View File

@@ -31,6 +31,7 @@ const (
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
NodeTaskTypeNetworkSecurityPolicyChanged NodeTaskType = "networkSecurityPolicyChanged" // 网络安全策略变化
NodeTaskTypeWebPPolicyChanged NodeTaskType = "webPPolicyChanged" // WebP策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化

View File

@@ -3,70 +3,82 @@ 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" // 每日访问量额度
PlanField_Id dbs.FieldName = "id" // ID
PlanField_IsOn dbs.FieldName = "isOn" // 是否启用
PlanField_Name dbs.FieldName = "name" // 套餐名
PlanField_Description dbs.FieldName = "description" // 描述
PlanField_ClusterId dbs.FieldName = "clusterId" // 集群ID
PlanField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
PlanField_Features dbs.FieldName = "features" // 允许的功能
PlanField_HasFullFeatures dbs.FieldName = "hasFullFeatures" // 是否有完整的功能
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" // 每日访问量额度
PlanField_DailyWebsocketConnections dbs.FieldName = "dailyWebsocketConnections" // 每日Websocket连接数
PlanField_MonthlyWebsocketConnections dbs.FieldName = "monthlyWebsocketConnections" // 每月Websocket连接数
)
// 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"` // 状态
TotalServers uint32 `field:"totalServers"` // 可以绑定的网站数量
TotalServerNamesPerServer uint32 `field:"totalServerNamesPerServer"` // 每个网站可以绑定的域名数量
TotalServerNames uint32 `field:"totalServerNames"` // 总域名数量
MonthlyRequests uint64 `field:"monthlyRequests"` // 每月访问量额度
DailyRequests uint64 `field:"dailyRequests"` // 每日访问量额度
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名
Description string `field:"description"` // 描述
ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能
HasFullFeatures bool `field:"hasFullFeatures"` // 是否有完整的功能
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"` // 每日访问量额度
DailyWebsocketConnections uint64 `field:"dailyWebsocketConnections"` // 每日Websocket连接数
MonthlyWebsocketConnections uint64 `field:"monthlyWebsocketConnections"` // 每月Websocket连接数
}
type PlanOperator struct {
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 // 每日访问量额度
Id any // ID
IsOn any // 是否启用
Name any // 套餐名
Description any // 描述
ClusterId any // 集群ID
TrafficLimit any // 流量限制
Features any // 允许的功能
HasFullFeatures 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 // 每日访问量额度
DailyWebsocketConnections any // 每日Websocket连接数
MonthlyWebsocketConnections any // 每月Websocket连接数
}
func NewPlanOperator() *PlanOperator {

View File

@@ -59,7 +59,7 @@ func init() {
// 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 {
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, countWebsocketConnections int64) error {
if userId <= 0 || userPlanId <= 0 {
return nil
}
@@ -73,29 +73,32 @@ func (this *UserPlanBandwidthStatDAO) UpdateUserPlanBandwidth(tx *dbs.Tx, userId
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
Param("countWebsocketConnections", countWebsocketConnections).
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,
"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,
"countWebsocketConnections": countWebsocketConnections,
}, 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"),
"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"),
"countWebsocketConnections": dbs.SQL("countWebsocketConnections+:countWebsocketConnections"),
})
}

View File

@@ -3,55 +3,58 @@ 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" // 攻击请求数
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" // 攻击请求数
UserPlanBandwidthStatField_CountWebsocketConnections dbs.FieldName = "countWebsocketConnections" // Websocket连接数
)
// 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"` // 攻击请求数
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"` // 攻击请求数
CountWebsocketConnections uint64 `field:"countWebsocketConnections"` // Websocket连接数
}
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 // 攻击请求数
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 // 攻击请求数
CountWebsocketConnections any // Websocket连接数
}
func NewUserPlanBandwidthStatOperator() *UserPlanBandwidthStatOperator {

View File

@@ -5,6 +5,6 @@ package models
import "github.com/iwind/TeaGo/dbs"
func (this *UserPlanStatDAO) IncreaseUserPlanStat(tx *dbs.Tx, userPlanId int64, trafficBytes int64, countRequests int64) error {
func (this *UserPlanStatDAO) IncreaseUserPlanStat(tx *dbs.Tx, userPlanId int64, trafficBytes int64, countRequests int64, countWebsocketConnections int64) error {
return nil
}

View File

@@ -3,34 +3,37 @@ 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" // 是否已处理
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_CountWebsocketConnections dbs.FieldName = "countWebsocketConnections" // Websocket连接数
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"` // 是否已处理
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"` // 总请求数
CountWebsocketConnections uint64 `field:"countWebsocketConnections"` // Websocket连接数
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 // 是否已处理
Id any // ID
UserPlanId any // 用户套餐ID
Date any // 日期YYYYMMDD或YYYYMM
DateType any // 日期类型day|month
TrafficBytes any // 流量
CountRequests any // 总请求数
CountWebsocketConnections any // Websocket连接数
IsProcessed any // 是否已处理
}
func NewUserPlanStatOperator() *UserPlanStatOperator {

View File

@@ -0,0 +1,33 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
UserScriptStateEnabled = 1 // 已启用
UserScriptStateDisabled = 0 // 已禁用
)
type UserScriptDAO dbs.DAO
func NewUserScriptDAO() *UserScriptDAO {
return dbs.NewDAO(&UserScriptDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserScripts",
Model: new(UserScript),
PkName: "id",
},
}).(*UserScriptDAO)
}
var SharedUserScriptDAO *UserScriptDAO
func init() {
dbs.OnReady(func() {
SharedUserScriptDAO = NewUserScriptDAO()
})
}

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,56 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
UserScriptField_Id dbs.FieldName = "id" // ID
UserScriptField_UserId dbs.FieldName = "userId" // 用户ID
UserScriptField_AdminId dbs.FieldName = "adminId" // 操作管理员
UserScriptField_Code dbs.FieldName = "code" // 代码
UserScriptField_CodeMD5 dbs.FieldName = "codeMD5" // 代码MD5
UserScriptField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
UserScriptField_IsRejected dbs.FieldName = "isRejected" // 是否已驳回
UserScriptField_RejectedAt dbs.FieldName = "rejectedAt" // 驳回时间
UserScriptField_RejectedReason dbs.FieldName = "rejectedReason" // 驳回原因
UserScriptField_IsPassed dbs.FieldName = "isPassed" // 是否通过审核
UserScriptField_PassedAt dbs.FieldName = "passedAt" // 通过时间
UserScriptField_State dbs.FieldName = "state" // 状态
UserScriptField_WebIds dbs.FieldName = "webIds" // WebId列表
)
// UserScript 用户脚本审核
type UserScript struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
AdminId uint64 `field:"adminId"` // 操作管理员
Code string `field:"code"` // 代码
CodeMD5 string `field:"codeMD5"` // 代码MD5
CreatedAt uint64 `field:"createdAt"` // 创建时间
IsRejected bool `field:"isRejected"` // 是否已驳回
RejectedAt uint64 `field:"rejectedAt"` // 驳回时间
RejectedReason string `field:"rejectedReason"` // 驳回原因
IsPassed bool `field:"isPassed"` // 是否通过审核
PassedAt uint64 `field:"passedAt"` // 通过时间
State uint8 `field:"state"` // 状态
WebIds dbs.JSON `field:"webIds"` // WebId列表
}
type UserScriptOperator struct {
Id any // ID
UserId any // 用户ID
AdminId any // 操作管理员
Code any // 代码
CodeMD5 any // 代码MD5
CreatedAt any // 创建时间
IsRejected any // 是否已驳回
RejectedAt any // 驳回时间
RejectedReason any // 驳回原因
IsPassed any // 是否通过审核
PassedAt any // 通过时间
State any // 状态
WebIds any // WebId列表
}
func NewUserScriptOperator() *UserScriptOperator {
return &UserScriptOperator{}
}

View File

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

View File

@@ -128,7 +128,7 @@ func (this *AliDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
}
for _, line := range resp.RecordLines.RecordLine {
routes = append(routes, &dnstypes.Route{
Name: line.LineName,
Name: line.LineDisplayName,
Code: line.LineCode,
})
}

View File

@@ -177,13 +177,12 @@ func (this *HuaweiDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Rout
{
Code: "Pengboshi",
Name: "鹏博士",
},
{
Code: "CN",
Name: "中国",
Name: "中国大陆",
},
{
@@ -192,6 +191,944 @@ func (this *HuaweiDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Rout
},
}...)
// 运营商线路细分
routes = append(routes, []*dnstypes.Route{
{
Code: "Dianxin_Huabei",
Name: "电信_华北地区",
},
{
Code: "Dianxin_Dongbei",
Name: "电信_东北地区",
},
{
Code: "Dianxin_Huadong",
Name: "电信_华东地区",
},
{
Code: "Dianxin_Huazhong",
Name: "电信_华中地区",
},
{
Code: "Dianxin_Huanan",
Name: "电信_华南地区",
},
{
Code: "Dianxin_Xinan",
Name: "电信_西南地区",
},
{
Code: "Dianxin_Xibei",
Name: "电信_西北地区",
},
{
Code: "Dianxin_Beijing",
Name: "电信_北京",
},
{
Code: "Dianxin_Hebei",
Name: "电信_河北",
},
{
Code: "Dianxin_Tianjin",
Name: "电信_天津",
},
{
Code: "Dianxin_Shanxi",
Name: "电信_山西",
},
{
Code: "Dianxin_Neimenggu",
Name: "电信_内蒙古",
},
{
Code: "Dianxin_Heilongjiang",
Name: "电信_黑龙江",
},
{
Code: "Dianxin_Jilin",
Name: "电信_吉林",
},
{
Code: "Dianxin_Liaoning",
Name: "电信_辽宁",
},
{
Code: "Dianxin_Jiangsu",
Name: "电信_江苏",
},
{
Code: "Dianxin_Shanghai",
Name: "电信_上海",
},
{
Code: "Dianxin_Zhejiang",
Name: "电信_浙江",
},
{
Code: "Dianxin_Anhui",
Name: "电信_安徽",
},
{
Code: "Dianxin_Fujian",
Name: "电信_福建",
},
{
Code: "Dianxin_Jiangxi",
Name: "电信_江西",
},
{
Code: "Dianxin_Shandong",
Name: "电信_山东",
},
{
Code: "Dianxin_Hubei",
Name: "电信_湖北",
},
{
Code: "Dianxin_Hunan",
Name: "电信_湖南",
},
{
Code: "Dianxin_Henan",
Name: "电信_河南",
},
{
Code: "Dianxin_Guangdong",
Name: "电信_广东",
},
{
Code: "Dianxin_Guangxi",
Name: "电信_广西",
},
{
Code: "Dianxin_Hainan",
Name: "电信_海南",
},
{
Code: "Dianxin_Sichuan",
Name: "电信_四川",
},
{
Code: "Dianxin_Xizang",
Name: "电信_西藏",
},
{
Code: "Dianxin_Chongqing",
Name: "电信_重庆",
},
{
Code: "Dianxin_Yunnan",
Name: "电信_云南",
},
{
Code: "Dianxin_Guizhou",
Name: "电信_贵州",
},
{
Code: "Dianxin_Gansu",
Name: "电信_甘肃",
},
{
Code: "Dianxin_Xinjiang",
Name: "电信_新疆",
},
{
Code: "Dianxin_Shaanxi",
Name: "电信_陕西",
},
{
Code: "Dianxin_Qinghai",
Name: "电信_青海",
},
{
Code: "Dianxin_Ningxia",
Name: "电信_宁夏",
},
{
Code: "Yidong_Huabei",
Name: "移动_华北地区",
},
{
Code: "Yidong_Dongbei",
Name: "移动_东北地区",
},
{
Code: "Yidong_Huadong",
Name: "移动_华东地区",
},
{
Code: "Yidong_Huazhong",
Name: "移动_华中地区",
},
{
Code: "Yidong_Huanan",
Name: "移动_华南地区",
},
{
Code: "Yidong_Xinan",
Name: "移动_西南地区",
},
{
Code: "Yidong_Xibei",
Name: "移动_西北地区",
},
{
Code: "Yidong_Beijing",
Name: "移动_北京",
},
{
Code: "Yidong_Hebei",
Name: "移动_河北",
},
{
Code: "Yidong_Tianjin",
Name: "移动_天津",
},
{
Code: "Yidong_Shanxi",
Name: "移动_山西",
},
{
Code: "Yidong_Neimenggu",
Name: "移动_内蒙古",
},
{
Code: "Yidong_Heilongjiang",
Name: "移动_黑龙江",
},
{
Code: "Yidong_Jilin",
Name: "移动_吉林",
},
{
Code: "Yidong_Liaoning",
Name: "移动_辽宁",
},
{
Code: "Yidong_Jiangsu",
Name: "移动_江苏",
},
{
Code: "Yidong_Shanghai",
Name: "移动_上海",
},
{
Code: "Yidong_Zhejiang",
Name: "移动_浙江",
},
{
Code: "Yidong_Anhui",
Name: "移动_安徽",
},
{
Code: "Yidong_Fujian",
Name: "移动_福建",
},
{
Code: "Yidong_Jiangxi",
Name: "移动_江西",
},
{
Code: "Yidong_Shandong",
Name: "移动_山东",
},
{
Code: "Yidong_Hubei",
Name: "移动_湖北",
},
{
Code: "Yidong_Hunan",
Name: "移动_湖南",
},
{
Code: "Yidong_Henan",
Name: "移动_河南",
},
{
Code: "Yidong_Guangdong",
Name: "移动_广东",
},
{
Code: "Yidong_Guangxi",
Name: "移动_广西",
},
{
Code: "Yidong_Hainan",
Name: "移动_海南",
},
{
Code: "Yidong_Sichuan",
Name: "移动_四川",
},
{
Code: "Yidong_Xizang",
Name: "移动_西藏",
},
{
Code: "Yidong_Chongqing",
Name: "移动_重庆",
},
{
Code: "Yidong_Yunnan",
Name: "移动_云南",
},
{
Code: "Yidong_Guizhou",
Name: "移动_贵州",
},
{
Code: "Yidong_Gansu",
Name: "移动_甘肃",
},
{
Code: "Yidong_Xinjiang",
Name: "移动_新疆",
},
{
Code: "Yidong_Shaanxi",
Name: "移动_陕西",
},
{
Code: "Yidong_Qinghai",
Name: "移动_青海",
},
{
Code: "Yidong_Ningxia",
Name: "移动_宁夏",
},
{
Code: "Liantong_Huabei",
Name: "联通_华北地区",
},
{
Code: "Liantong_Dongbei",
Name: "联通_东北地区",
},
{
Code: "Liantong_Huadong",
Name: "联通_华东地区",
},
{
Code: "Liantong_Huazhong",
Name: "联通_华中地区",
},
{
Code: "Liantong_Huanan",
Name: "联通_华南地区",
},
{
Code: "Liantong_Xinan",
Name: "联通_西南地区",
},
{
Code: "Liantong_Xibei",
Name: "联通_西北地区",
},
{
Code: "Liantong_Beijing",
Name: "联通_北京",
},
{
Code: "Liantong_Hebei",
Name: "联通_河北",
},
{
Code: "Liantong_Tianjin",
Name: "联通_天津",
},
{
Code: "Liantong_Shanxi",
Name: "联通_山西",
},
{
Code: "Liantong_Neimenggu",
Name: "联通_内蒙古",
},
{
Code: "Liantong_Heilongjiang",
Name: "联通_黑龙江",
},
{
Code: "Liantong_Jilin",
Name: "联通_吉林",
},
{
Code: "Liantong_Liaoning",
Name: "联通_辽宁",
},
{
Code: "Liantong_Jiangsu",
Name: "联通_江苏",
},
{
Code: "Liantong_Shanghai",
Name: "联通_上海",
},
{
Code: "Liantong_Zhejiang",
Name: "联通_浙江",
},
{
Code: "Liantong_Anhui",
Name: "联通_安徽",
},
{
Code: "Liantong_Fujian",
Name: "联通_福建",
},
{
Code: "Liantong_Jiangxi",
Name: "联通_江西",
},
{
Code: "Liantong_Shandong",
Name: "联通_山东",
},
{
Code: "Liantong_Hubei",
Name: "联通_湖北",
},
{
Code: "Liantong_Hunan",
Name: "联通_湖南",
},
{
Code: "Liantong_Henan",
Name: "联通_河南",
},
{
Code: "Liantong_Guangdong",
Name: "联通_广东",
},
{
Code: "Liantong_Guangxi",
Name: "联通_广西",
},
{
Code: "Liantong_Hainan",
Name: "联通_海南",
},
{
Code: "Liantong_Sichuan",
Name: "联通_四川",
},
{
Code: "Liantong_Xizang",
Name: "联通_西藏",
},
{
Code: "Liantong_Chongqing",
Name: "联通_重庆",
},
{
Code: "Liantong_Yunnan",
Name: "联通_云南",
},
{
Code: "Liantong_Guizhou",
Name: "联通_贵州",
},
{
Code: "Liantong_Gansu",
Name: "联通_甘肃",
},
{
Code: "Liantong_Xinjiang",
Name: "联通_新疆",
},
{
Code: "Liantong_Shaanxi",
Name: "联通_陕西",
},
{
Code: "Liantong_Qinghai",
Name: "联通_青海",
},
{
Code: "Liantong_Ningxia",
Name: "联通_宁夏",
},
{
Code: "Jiaoyuwang",
Name: "教育网默认",
},
{
Code: "Jiaoyuwang_Huabei",
Name: "教育网_华北地区",
},
{
Code: "Jiaoyuwang_Dongbei",
Name: "教育网_东北地区",
},
{
Code: "Jiaoyuwang_Huadong",
Name: "教育网_华东地区",
},
{
Code: "Jiaoyuwang_Huazhong",
Name: "教育网_华中地区",
},
{
Code: "Jiaoyuwang_Huanan",
Name: "教育网_华南地区",
},
{
Code: "Jiaoyuwang_Xinan",
Name: "教育网_西南地区",
},
{
Code: "Jiaoyuwang_Xibei",
Name: "教育网_西北地区",
},
{
Code: "Jiaoyuwang_Beijing",
Name: "教育网_北京",
},
{
Code: "Jiaoyuwang_Hebei",
Name: "教育网_河北",
},
{
Code: "Jiaoyuwang_Tianjin",
Name: "教育网_天津",
},
{
Code: "Jiaoyuwang_Shanxi",
Name: "教育网_山西",
},
{
Code: "Jiaoyuwang_Neimenggu",
Name: "教育网_内蒙古",
},
{
Code: "Jiaoyuwang_Heilongjiang",
Name: "教育网_黑龙江",
},
{
Code: "Jiaoyuwang_Jilin",
Name: "教育网_吉林",
},
{
Code: "Jiaoyuwang_Liaoning",
Name: "教育网_辽宁",
},
{
Code: "Jiaoyuwang_Jiangsu",
Name: "教育网_江苏",
},
{
Code: "Jiaoyuwang_Shanghai",
Name: "教育网_上海",
},
{
Code: "Jiaoyuwang_Zhejiang",
Name: "教育网_浙江",
},
{
Code: "Jiaoyuwang_Anhui",
Name: "教育网_安徽",
},
{
Code: "Jiaoyuwang_Fujian",
Name: "教育网_福建",
},
{
Code: "Jiaoyuwang_Jiangxi",
Name: "教育网_江西",
},
{
Code: "Jiaoyuwang_Shandong",
Name: "教育网_山东",
},
{
Code: "Jiaoyuwang_Hubei",
Name: "教育网_湖北",
},
{
Code: "Jiaoyuwang_Hunan",
Name: "教育网_湖南",
},
{
Code: "Jiaoyuwang_Henan",
Name: "教育网_河南",
},
{
Code: "Jiaoyuwang_Guangdong",
Name: "教育网_广东",
},
{
Code: "Jiaoyuwang_Guangxi",
Name: "教育网_广西",
},
{
Code: "Jiaoyuwang_Hainan",
Name: "教育网_海南",
},
{
Code: "Jiaoyuwang_Sichuan",
Name: "教育网_四川",
},
{
Code: "Jiaoyuwang_Xizang",
Name: "教育网_西藏",
},
{
Code: "Jiaoyuwang_Chongqing",
Name: "教育网_重庆",
},
{
Code: "Jiaoyuwang_Yunnan",
Name: "教育网_云南",
},
{
Code: "Jiaoyuwang_Guizhou",
Name: "教育网_贵州",
},
{
Code: "Jiaoyuwang_Gansu",
Name: "教育网_甘肃",
},
{
Code: "Jiaoyuwang_Xinjiang",
Name: "教育网_新疆",
},
{
Code: "Jiaoyuwang_Shaanxi",
Name: "教育网_陕西",
},
{
Code: "Jiaoyuwang_Qinghai",
Name: "教育网_青海",
},
{
Code: "Jiaoyuwang_Ningxia",
Name: "教育网_宁夏",
},
{
Code: "Pengboshi",
Name: "鹏博士默认",
},
{
Code: "Pengboshi_Huabei",
Name: "鹏博士_华北地区",
},
{
Code: "Pengboshi_Dongbei",
Name: "鹏博士_东北地区",
},
{
Code: "Pengboshi_Huadong",
Name: "鹏博士_华东地区",
},
{
Code: "Pengboshi_Huazhong",
Name: "鹏博士_华中地区",
},
{
Code: "Pengboshi_Huanan",
Name: "鹏博士_华南地区",
},
{
Code: "Pengboshi_Xinan",
Name: "鹏博士_西南",
},
{
Code: "Pengboshi_Xibei",
Name: "鹏博士_西北",
},
{
Code: "Pengboshi_Beijing",
Name: "鹏博士_北京",
},
{
Code: "Pengboshi_Hebei",
Name: "鹏博士_河北",
},
{
Code: "Pengboshi_Tianjin",
Name: "鹏博士_天津",
},
{
Code: "Pengboshi_Shanxi",
Name: "鹏博士_山西",
},
{
Code: "Pengboshi_Neimenggu",
Name: "鹏博士_内蒙古",
},
{
Code: "Pengboshi_Heilongjiang",
Name: "鹏博士_黑龙江",
},
{
Code: "Pengboshi_Jilin",
Name: "鹏博士_吉林",
},
{
Code: "Pengboshi_Liaoning",
Name: "鹏博士_辽宁",
},
{
Code: "Pengboshi_Jiangsu",
Name: "鹏博士_江苏",
},
{
Code: "Pengboshi_Shanghai",
Name: "鹏博士_上海",
},
{
Code: "Pengboshi_Zhejiang",
Name: "鹏博士_浙江",
},
{
Code: "Pengboshi_Anhui",
Name: "鹏博士_安徽",
},
{
Code: "Pengboshi_Fujian",
Name: "鹏博士_福建",
},
{
Code: "Pengboshi_Jiangxi",
Name: "鹏博士_江西",
},
{
Code: "Pengboshi_Shandong",
Name: "鹏博士_山东",
},
{
Code: "Pengboshi_Hubei",
Name: "鹏博士_湖北",
},
{
Code: "Pengboshi_Hunan",
Name: "鹏博士_湖南",
},
{
Code: "Pengboshi_Henan",
Name: "鹏博士_河南",
},
{
Code: "Pengboshi_Guangdong",
Name: "鹏博士_广东",
},
{
Code: "Pengboshi_Guangxi",
Name: "鹏博士_广西",
},
{
Code: "Pengboshi_Hainan",
Name: "鹏博士_海南",
},
{
Code: "Pengboshi_Sichuan",
Name: "鹏博士_四川",
},
{
Code: "Pengboshi_Xizang",
Name: "鹏博士_西藏",
},
{
Code: "Pengboshi_Chongqing",
Name: "鹏博士_重庆",
},
{
Code: "Pengboshi_Yunnan",
Name: "鹏博士_云南",
},
{
Code: "Pengboshi_Guizhou",
Name: "鹏博士_贵州",
},
{
Code: "Pengboshi_Gansu",
Name: "鹏博士_甘肃",
},
{
Code: "Pengboshi_Xinjiang",
Name: "鹏博士_新疆",
},
{
Code: "Pengboshi_Shaanxi",
Name: "鹏博士_陕西",
},
{
Code: "Pengboshi_Qinghai",
Name: "鹏博士_青海",
},
{
Code: "Pengboshi_Ningxia",
Name: "鹏博士_宁夏",
},
{
Code: "Tietong",
Name: "铁通默认",
},
{
Code: "Tietong_Huabei",
Name: "铁通_华北地区",
},
{
Code: "Tietong_Dongbei",
Name: "铁通_东北地区",
},
{
Code: "Tietong_Huadong",
Name: "铁通_华东地区",
},
{
Code: "Tietong_Huazhong",
Name: "铁通_华中地区",
},
{
Code: "Tietong_Huanan",
Name: "铁通_华南地区",
},
{
Code: "Tietong_Xinan",
Name: "铁通_西南地区",
},
{
Code: "Tietong_Xibei",
Name: "铁通_西北地区",
},
{
Code: "Tietong_Beijing",
Name: "铁通_北京",
},
{
Code: "Tietong_Hebei",
Name: "铁通_河北",
},
{
Code: "Tietong_Tianjin",
Name: "铁通_天津",
},
{
Code: "Tietong_Shanxi",
Name: "铁通_山西",
},
{
Code: "Tietong_Neimenggu",
Name: "铁通_内蒙古",
},
{
Code: "Tietong_Heilongjiang",
Name: "铁通_黑龙江",
},
{
Code: "Tietong_Jilin",
Name: "铁通_吉林",
},
{
Code: "Tietong_Liaoning",
Name: "铁通_辽宁",
},
{
Code: "Tietong_Jiangsu",
Name: "铁通_江苏",
},
{
Code: "Tietong_Shanghai",
Name: "铁通_上海",
},
{
Code: "Tietong_Zhejiang",
Name: "铁通_浙江",
},
{
Code: "Tietong_Anhui",
Name: "铁通_安徽",
},
{
Code: "Tietong_Fujian",
Name: "铁通_福建",
},
{
Code: "Tietong_Jiangxi",
Name: "铁通_江西",
},
{
Code: "Tietong_Shandong",
Name: "铁通_山东",
},
{
Code: "Tietong_Hubei",
Name: "铁通_湖北",
},
{
Code: "Tietong_Hunan",
Name: "铁通_湖南",
},
{
Code: "Tietong_Henan",
Name: "铁通_河南",
},
{
Code: "Tietong_Guangdong",
Name: "铁通_广东",
},
{
Code: "Tietong_Guangxi",
Name: "铁通_广西",
},
{
Code: "Tietong_Hainan",
Name: "铁通_海南",
},
{
Code: "Tietong_Sichuan",
Name: "铁通_四川",
},
{
Code: "Tietong_Xizang",
Name: "铁通_西藏",
},
{
Code: "Tietong_Chongqing",
Name: "铁通_重庆",
},
{
Code: "Tietong_Yunnan",
Name: "铁通_云南",
},
{
Code: "Tietong_Guizhou",
Name: "铁通_贵州",
},
{
Code: "Tietong_Gansu",
Name: "铁通_甘肃",
},
{
Code: "Tietong_Xinjiang",
Name: "铁通_新疆",
},
{
Code: "Tietong_Shaanxi",
Name: "铁通_陕西",
},
{
Code: "Tietong_Qinghai",
Name: "铁通_青海",
},
{
Code: "Tietong_Ningxia",
Name: "铁通_宁夏",
},
}...)
// 地域线路细分(全球)
routes = append(routes, []*dnstypes.Route{
{

View File

@@ -740,3 +740,18 @@ func (this *AdminService) UpdateAdminTheme(ctx context.Context, req *pb.UpdateAd
}
return this.Success()
}
// UpdateAdminLang 修改管理员使用的语言
func (this *AdminService) UpdateAdminLang(ctx context.Context, req *pb.UpdateAdminLangRequest) (*pb.RPCSuccess, error) {
adminId, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedAdminDAO.UpdateAdminLang(tx, adminId, req.LangCode)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -33,7 +33,7 @@ func (this *HTTPFirewallPolicyService) FindAllEnabledHTTPFirewallPolicies(ctx co
return nil, err
}
result := []*pb.HTTPFirewallPolicy{}
var result = []*pb.HTTPFirewallPolicy{}
for _, p := range policies {
result = append(result, &pb.HTTPFirewallPolicy{
Id: int64(p.Id),
@@ -395,7 +395,7 @@ func (this *HTTPFirewallPolicyService) ListEnabledHTTPFirewallPolicies(ctx conte
return nil, err
}
result := []*pb.HTTPFirewallPolicy{}
var result = []*pb.HTTPFirewallPolicy{}
for _, p := range policies {
result = append(result, &pb.HTTPFirewallPolicy{
Id: int64(p.Id),
@@ -488,17 +488,21 @@ func (this *HTTPFirewallPolicyService) FindEnabledHTTPFirewallPolicy(ctx context
if policy == nil {
return &pb.FindEnabledHTTPFirewallPolicyResponse{HttpFirewallPolicy: nil}, nil
}
return &pb.FindEnabledHTTPFirewallPolicyResponse{HttpFirewallPolicy: &pb.HTTPFirewallPolicy{
Id: int64(policy.Id),
ServerId: int64(policy.ServerId),
Name: policy.Name,
Description: policy.Description,
IsOn: policy.IsOn,
InboundJSON: policy.Inbound,
OutboundJSON: policy.Outbound,
Mode: policy.Mode,
SynFloodJSON: policy.SynFlood,
}}, nil
return &pb.FindEnabledHTTPFirewallPolicyResponse{
HttpFirewallPolicy: &pb.HTTPFirewallPolicy{
Id: int64(policy.Id),
ServerId: int64(policy.ServerId),
Name: policy.Name,
Description: policy.Description,
IsOn: policy.IsOn,
InboundJSON: policy.Inbound,
OutboundJSON: policy.Outbound,
Mode: policy.Mode,
SynFloodJSON: policy.SynFlood,
BlockOptionsJSON: policy.BlockOptions,
CaptchaOptionsJSON: policy.CaptchaOptions,
},
}, nil
}
// ImportHTTPFirewallPolicy 导入策略数据
@@ -858,3 +862,29 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
RegionProvince: nil,
}, nil
}
// FindServerIdWithHTTPFirewallPolicyId 获取防火墙对应的网站ID
func (this *HTTPFirewallPolicyService) FindServerIdWithHTTPFirewallPolicyId(ctx context.Context, req *pb.FindServerIdWithHTTPFirewallPolicyIdRequest) (*pb.FindServerIdWithHTTPFirewallPolicyIdResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
serverId, err := models.SharedHTTPFirewallPolicyDAO.FindServerIdWithFirewallPolicyId(tx, req.HttpFirewallPolicyId)
if err != nil {
return nil, err
}
// check user
if serverId > 0 && userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, serverId)
if err != nil {
return nil, err
}
}
return &pb.FindServerIdWithHTTPFirewallPolicyIdResponse{
ServerId: serverId,
}, nil
}

View File

@@ -3,12 +3,16 @@ package services
import (
"context"
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils/domainutils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"strings"
)
type HTTPWebService struct {
@@ -532,6 +536,49 @@ func (this *HTTPWebService) UpdateHTTPWebCache(ctx context.Context, req *pb.Upda
var tx = this.NullTx()
var cacheConfig = &serverconfigs.HTTPCacheConfig{}
if len(req.CacheJSON) > 0 {
err = json.Unmarshal(req.CacheJSON, cacheConfig)
if err != nil {
return nil, err
}
err = cacheConfig.Init()
if err != nil {
return nil, fmt.Errorf("validate cache config failed: %w", err)
}
}
// validate host
if cacheConfig.Key != nil && cacheConfig.Key.IsOn {
if cacheConfig.Key.Scheme != "http" && cacheConfig.Key.Scheme != "https" {
return nil, errors.New("key scheme must be 'http' or 'https'")
}
cacheConfig.Key.Host = strings.ToLower(cacheConfig.Key.Host)
if !domainutils.ValidateDomainFormat(cacheConfig.Key.Host) {
return nil, errors.New("key host must be a valid domain")
}
serverId, err := models.SharedHTTPWebDAO.FindWebServerId(tx, req.HttpWebId)
if err != nil {
return nil, err
}
if serverId > 0 {
serverNamesJSON, _, _, _, _, err := models.SharedServerDAO.FindServerServerNames(tx, serverId)
if err != nil {
return nil, err
}
var serverNames = []*serverconfigs.ServerNameConfig{}
err = json.Unmarshal(serverNamesJSON, &serverNames)
if err != nil {
return nil, err
}
if !lists.ContainsString(serverconfigs.PlainServerNames(serverNames), cacheConfig.Key.Host) {
return nil, errors.New("key host '" + cacheConfig.Key.Host + "' not exists in server names")
}
}
}
err = models.SharedHTTPWebDAO.UpdateWebCache(tx, req.HttpWebId, req.CacheJSON)
if err != nil {
return nil, err
@@ -851,28 +898,6 @@ func (this *HTTPWebService) FindHTTPWebRequestLimit(ctx context.Context, req *pb
return &pb.FindHTTPWebRequestLimitResponse{RequestLimitJSON: configJSON}, nil
}
// UpdateHTTPWebRequestScripts 修改请求脚本
func (this *HTTPWebService) UpdateHTTPWebRequestScripts(ctx context.Context, req *pb.UpdateHTTPWebRequestScriptsRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var config = &serverconfigs.HTTPRequestScriptsConfig{}
err = json.Unmarshal(req.RequestScriptsJSON, config)
if err != nil {
return nil, err
}
err = models.SharedHTTPWebDAO.UpdateWebRequestScripts(tx, req.HttpWebId, config)
if err != nil {
return nil, err
}
return this.Success()
}
// FindHTTPWebRequestScripts 查找请求脚本
func (this *HTTPWebService) FindHTTPWebRequestScripts(ctx context.Context, req *pb.FindHTTPWebRequestScriptsRequest) (*pb.FindHTTPWebRequestScriptsResponse, error) {
_, err := this.ValidateAdmin(ctx)
@@ -1029,3 +1054,30 @@ func (this *HTTPWebService) FindHTTPWebUserAgent(ctx context.Context, req *pb.Fi
UserAgentJSON: configJSON,
}, nil
}
// FindServerIdWithHTTPWebId 根据WebId查找ServerId
func (this *HTTPWebService) FindServerIdWithHTTPWebId(ctx context.Context, req *pb.FindServerIdWithHTTPWebIdRequest) (*pb.FindServerIdWithHTTPWebIdResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if req.HttpWebId <= 0 {
return nil, errors.New("invalid 'httpWebId'")
}
var tx = this.NullTx()
serverId, err := models.SharedHTTPWebDAO.FindWebServerId(tx, req.HttpWebId)
if err != nil {
return nil, err
}
if serverId > 0 && userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, serverId)
if err != nil {
return nil, err
}
}
return &pb.FindServerIdWithHTTPWebIdResponse{ServerId: serverId}, nil
}

View File

@@ -27,3 +27,8 @@ func (this *HTTPWebService) UpdateHTTPWebCC(ctx context.Context, req *pb.UpdateH
func (this *HTTPWebService) FindHTTPWebCC(ctx context.Context, req *pb.FindHTTPWebCCRequest) (*pb.FindHTTPWebCCResponse, error) {
return nil, this.NotImplementedYet()
}
// UpdateHTTPWebRequestScripts 修改请求脚本
func (this *HTTPWebService) UpdateHTTPWebRequestScripts(ctx context.Context, req *pb.UpdateHTTPWebRequestScriptsRequest) (*pb.RPCSuccess, error) {
return nil, this.NotImplementedYet()
}

View File

@@ -768,6 +768,29 @@ func (this *IPItemService) ListAllEnabledIPItems(ctx context.Context, req *pb.Li
return &pb.ListAllEnabledIPItemsResponse{Results: results}, nil
}
// ListAllIPItemIds 列出所有名单中的IP ID
func (this *IPItemService) ListAllIPItemIds(ctx context.Context, req *pb.ListAllIPItemIdsRequest) (*pb.ListAllIPItemIdsResponse, error) {
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if adminId > 0 {
userId = req.UserId
}
var tx = this.NullTx()
var listId int64 = 0
if req.GlobalOnly {
listId = firewallconfigs.GlobalListId
}
itemIds, err := models.SharedIPItemDAO.ListAllIPItemIds(tx, userId, req.Keyword, req.Ip, listId, req.Unread, req.EventLevel, req.ListType, req.Offset, req.Size)
if err != nil {
return nil, err
}
return &pb.ListAllIPItemIdsResponse{IpItemIds: itemIds}, nil
}
// UpdateIPItemsRead 设置所有为已读
func (this *IPItemService) UpdateIPItemsRead(ctx context.Context, req *pb.UpdateIPItemsReadRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
@@ -782,3 +805,38 @@ func (this *IPItemService) UpdateIPItemsRead(ctx context.Context, req *pb.Update
}
return this.Success()
}
// FindServerIdWithIPItemId 查找IP对应的名单所属网站ID
func (this *IPItemService) FindServerIdWithIPItemId(ctx context.Context, req *pb.FindServerIdWithIPItemIdRequest) (*pb.FindServerIdWithIPItemIdResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId)
if err != nil {
return nil, err
}
if listId > 0 {
var serverId int64
serverId, err = models.SharedIPListDAO.FindServerIdWithListId(tx, listId)
if err != nil {
return nil, err
}
if serverId > 0 {
// check user
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, serverId)
if err != nil {
return nil, err
}
}
return &pb.FindServerIdWithIPItemIdResponse{ServerId: serverId}, nil
}
}
return &pb.FindServerIdWithIPItemIdResponse{ServerId: 0}, nil
}

View File

@@ -224,3 +224,29 @@ func (this *IPListService) FindEnabledIPListContainsIP(ctx context.Context, req
}
return &pb.FindEnabledIPListContainsIPResponse{IpLists: pbLists}, nil
}
// FindServerIdWithIPListId 查找IP名单对应的网站ID
func (this *IPListService) FindServerIdWithIPListId(ctx context.Context, req *pb.FindServerIdWithIPListIdRequest) (*pb.FindServerIdWithIPListIdResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
serverId, err := models.SharedIPListDAO.FindServerIdWithListId(tx, req.IpListId)
if err != nil {
return nil, err
}
// check user
if serverId > 0 && userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, serverId)
if err != nil {
return nil, err
}
}
return &pb.FindServerIdWithIPListIdResponse{
ServerId: serverId,
}, nil
}

View File

@@ -2257,3 +2257,39 @@ func (this *NodeService) UpdateNodeAPIConfig(ctx context.Context, req *pb.Update
return this.Success()
}
// FindNodeWebPPolicies 查找节点的WebP策略
func (this *NodeService) FindNodeWebPPolicies(ctx context.Context, req *pb.FindNodeWebPPoliciesRequest) (*pb.FindNodeWebPPoliciesResponse, error) {
nodeId, err := this.ValidateNode(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
clusterIds, err := models.SharedNodeDAO.FindEnabledAndOnNodeClusterIds(tx, nodeId)
if err != nil {
return nil, err
}
var pbPolicies = []*pb.FindNodeWebPPoliciesResponse_WebPPolicy{}
for _, clusterId := range clusterIds {
policy, err := models.SharedNodeClusterDAO.FindClusterWebPPolicy(tx, clusterId, nil)
if err != nil {
return nil, err
}
if policy == nil {
continue
}
policyJSON, err := json.Marshal(policy)
if err != nil {
return nil, err
}
pbPolicies = append(pbPolicies, &pb.FindNodeWebPPoliciesResponse_WebPPolicy{
NodeClusterId: clusterId,
WebPPolicyJSON: policyJSON,
})
}
return &pb.FindNodeWebPPoliciesResponse{
WebPPolicies: pbPolicies,
}, nil
}

View File

@@ -1126,14 +1126,14 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
// webp
if models.IsNotNull(cluster.Webp) {
var webpPolicy = &nodeconfigs.WebPImagePolicy{}
var webpPolicy = nodeconfigs.NewWebPImagePolicy()
err = json.Unmarshal(cluster.Webp, webpPolicy)
if err != nil {
return nil, err
}
result.WebpIsOn = webpPolicy.IsOn
result.WebPIsOn = webpPolicy.IsOn
} else {
result.WebpIsOn = nodeconfigs.DefaultWebPImagePolicy.IsOn
result.WebPIsOn = nodeconfigs.DefaultWebPImagePolicy.IsOn
}
// UAM
@@ -1247,8 +1247,8 @@ func (this *NodeClusterService) UpdateNodeClusterWebPPolicy(ctx context.Context,
return nil, err
}
var webpPolicy = &nodeconfigs.WebPImagePolicy{}
err = json.Unmarshal(req.WebpPolicyJSON, webpPolicy)
var webpPolicy = nodeconfigs.NewWebPImagePolicy()
err = json.Unmarshal(req.WebPPolicyJSON, webpPolicy)
if err != nil {
return nil, err
}

View File

@@ -48,3 +48,8 @@ func (this *PlanService) ListEnabledPlans(ctx context.Context, req *pb.ListEnabl
func (this *PlanService) SortPlans(ctx context.Context, req *pb.SortPlansRequest) (*pb.RPCSuccess, error) {
return this.Success()
}
// FindAllAvailablePlans 列出所有可用的套餐
func (this *PlanService) FindAllAvailablePlans(ctx context.Context, req *pb.FindAllAvailablePlansRequest) (*pb.FindAllAvailablePlansResponse, error) {
return nil, this.NotImplementedYet()
}

View File

@@ -2414,7 +2414,7 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
return this.Success()
}
// CheckServerNameDuplicationInNodeCluster 检查域名是否已经存在
// CheckServerNameDuplicationInNodeCluster 检查域名是否在集群中已经存在
func (this *ServerService) CheckServerNameDuplicationInNodeCluster(ctx context.Context, req *pb.CheckServerNameDuplicationInNodeClusterRequest) (*pb.CheckServerNameDuplicationInNodeClusterResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
@@ -2441,6 +2441,47 @@ func (this *ServerService) CheckServerNameDuplicationInNodeCluster(ctx context.C
return &pb.CheckServerNameDuplicationInNodeClusterResponse{DuplicatedServerNames: duplicatedServerNames}, nil
}
// CheckServerNameInServer 检查域名是否在网站中已经绑定
func (this *ServerService) CheckServerNameInServer(ctx context.Context, req *pb.CheckServerNameInServerRequest) (*pb.CheckServerNameInServerResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if req.ServerId <= 0 {
return nil, errors.New("invalid serverId '" + types.String(req.ServerId) + "'")
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
if err != nil {
return nil, err
}
}
if len(req.ServerName) == 0 {
return &pb.CheckServerNameInServerResponse{
Exists: false,
}, nil
}
serverNamesJSON, _, _, _, _, err := models.SharedServerDAO.FindServerServerNames(tx, req.ServerId)
if err != nil {
return nil, err
}
var serverNames = []*serverconfigs.ServerNameConfig{}
err = json.Unmarshal(serverNamesJSON, &serverNames)
if err != nil {
return nil, err
}
return &pb.CheckServerNameInServerResponse{
Exists: lists.ContainsString(serverconfigs.PlainServerNames(serverNames), req.ServerName),
}, nil
}
// FindLatestServers 查找最近访问的服务
func (this *ServerService) FindLatestServers(ctx context.Context, req *pb.FindLatestServersRequest) (*pb.FindLatestServersResponse, error) {
_, err := this.ValidateAdmin(ctx)
@@ -2849,6 +2890,7 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
User: nil,
Plan: &pb.Plan{
Id: int64(plan.Id),
IsOn: plan.IsOn,
Name: plan.Name,
PriceType: plan.PriceType,
TrafficPriceJSON: plan.TrafficPrice,
@@ -2856,6 +2898,8 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
TotalServers: types.Int32(plan.TotalServers),
TotalServerNames: types.Int32(plan.TotalServerNames),
TotalServerNamesPerServer: types.Int32(plan.TotalServerNamesPerServer),
HasFullFeatures: plan.HasFullFeatures,
FeaturesJSON: plan.Features,
},
},
}, nil

View File

@@ -80,13 +80,13 @@ func init() {
// 套餐统计
if stat.UserPlanId > 0 {
// 总体统计
err = models.SharedUserPlanStatDAO.IncreaseUserPlanStat(tx, stat.UserPlanId, stat.TotalBytes, stat.CountRequests)
err = models.SharedUserPlanStatDAO.IncreaseUserPlanStat(tx, stat.UserPlanId, stat.TotalBytes, stat.CountRequests, stat.CountWebsocketConnections)
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)
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, stat.CountWebsocketConnections)
}
}
@@ -146,22 +146,24 @@ func (this *ServerBandwidthStatService) UploadServerBandwidthStats(ctx context.C
oldStat.CountRequests += stat.CountRequests
oldStat.CountCachedRequests += stat.CountCachedRequests
oldStat.CountAttackRequests += stat.CountAttackRequests
oldStat.CountWebsocketConnections += stat.CountWebsocketConnections
} else {
serverBandwidthStatsMap[key] = &pb.ServerBandwidthStat{
Id: 0,
NodeRegionId: stat.NodeRegionId,
UserId: stat.UserId,
ServerId: stat.ServerId,
Day: stat.Day,
TimeAt: stat.TimeAt,
Bytes: stat.Bytes,
TotalBytes: stat.TotalBytes,
CachedBytes: stat.CachedBytes,
AttackBytes: stat.AttackBytes,
CountRequests: stat.CountRequests,
CountCachedRequests: stat.CountCachedRequests,
CountAttackRequests: stat.CountAttackRequests,
UserPlanId: stat.UserPlanId,
Id: 0,
NodeRegionId: stat.NodeRegionId,
UserId: stat.UserId,
ServerId: stat.ServerId,
Day: stat.Day,
TimeAt: stat.TimeAt,
Bytes: stat.Bytes,
TotalBytes: stat.TotalBytes,
CachedBytes: stat.CachedBytes,
AttackBytes: stat.AttackBytes,
CountRequests: stat.CountRequests,
CountCachedRequests: stat.CountCachedRequests,
CountAttackRequests: stat.CountAttackRequests,
CountWebsocketConnections: stat.CountWebsocketConnections,
UserPlanId: stat.UserPlanId,
}
}
serverBandwidthStatsLocker.Unlock()

View File

@@ -618,31 +618,6 @@ func (this *UserService) UpdateAllUsersFeatures(ctx context.Context, req *pb.Upd
return this.Success()
}
// FindUserFeatures 获取用户所有的功能列表
func (this *UserService) FindUserFeatures(ctx context.Context, req *pb.FindUserFeaturesRequest) (*pb.FindUserFeaturesResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
features, err := models.SharedUserDAO.FindUserFeatures(tx, req.UserId)
if err != nil {
return nil, err
}
result := []*pb.UserFeature{}
for _, feature := range features {
result = append(result, feature.ToPB())
}
return &pb.FindUserFeaturesResponse{Features: result}, nil
}
// FindAllUserFeatureDefinitions 获取所有的功能定义
func (this *UserService) FindAllUserFeatureDefinitions(ctx context.Context, req *pb.FindAllUserFeatureDefinitionsRequest) (*pb.FindAllUserFeatureDefinitionsResponse, error) {
_, err := this.ValidateAdmin(ctx)
@@ -650,8 +625,8 @@ func (this *UserService) FindAllUserFeatureDefinitions(ctx context.Context, req
return nil, err
}
features := userconfigs.FindAllUserFeatures()
result := []*pb.UserFeature{}
var features = userconfigs.FindAllUserFeatures()
var result = []*pb.UserFeature{}
for _, feature := range features {
result = append(result, feature.ToPB())
}

View File

@@ -89,3 +89,28 @@ func (this *UserService) RegisterUser(ctx context.Context, req *pb.RegisterUserR
RequireEmailVerification: requireEmailVerification,
}, nil
}
// FindUserFeatures 获取用户所有的功能列表
func (this *UserService) FindUserFeatures(ctx context.Context, req *pb.FindUserFeaturesRequest) (*pb.FindUserFeaturesResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
features, err := models.SharedUserDAO.FindUserFeatures(tx, req.UserId)
if err != nil {
return nil, err
}
result := []*pb.UserFeature{}
for _, feature := range features {
result = append(result, feature.ToPB())
}
return &pb.FindUserFeaturesResponse{Features: result}, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
package setup
import (
"crypto/rand"
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
@@ -259,7 +260,16 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
return err
}
_, err = db.Exec("INSERT INTO edgeNodeClusters (name, useAllAPINodes, state, uniqueId, secret, dns) VALUES (?, ?, ?, ?, ?, ?)", "默认集群", 1, 1, uniqueId, secret, string(clusterDNSConfigJSON))
var defaultDNSName = "g" + rands.HexString(6) + ".cdn"
{
var b = make([]byte, 3)
_, err = rand.Read(b)
if err == nil {
defaultDNSName = fmt.Sprintf("g%x.cdn", b)
}
}
_, err = db.Exec("INSERT INTO edgeNodeClusters (name, useAllAPINodes, state, uniqueId, secret, dns, dnsName) VALUES (?, ?, ?, ?, ?, ?, ?)", "默认集群", 1, 1, uniqueId, secret, string(clusterDNSConfigJSON), defaultDNSName)
if err != nil {
return err
}

View File

@@ -11,12 +11,14 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
"strconv"
"strings"
)
@@ -101,6 +103,9 @@ var upgradeFuncs = []*upgradeVersion{
{
"1.2.10", upgradeV1_2_10,
},
{
"1.3.2", upgradeV1_3_2,
},
}
// UpgradeSQLData 升级SQL数据
@@ -816,3 +821,412 @@ func upgradeV1_2_10(db *dbs.DB) error {
return nil
}
// 1.3.2
func upgradeV1_3_2(db *dbs.DB) error {
// waf
{
var disableSet = func(setId int64) error {
_, err := db.Exec("UPDATE edgeHTTPFirewallRuleSets SET state=0 WHERE id=?", setId)
return err
}
var addRuleToGroup = func(groupId int64, setCode string, setName string, actions []*firewallconfigs.HTTPFirewallActionConfig, ruleParam string, ruleOperator string, value string) error {
actionsJSON, err := json.Marshal(actions)
if err != nil {
return err
}
// rule
ruleResult, err := db.Exec("INSERT INTO edgeHTTPFirewallRules (isOn, param, operator, value, isCaseInsensitive, state) VALUES (1, ?, ?, ?, 0, 1)", ruleParam, ruleOperator, value)
if err != nil {
return err
}
ruleId, err := ruleResult.LastInsertId()
if err != nil {
return err
}
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{
{
IsOn: true,
RuleId: ruleId,
},
}
ruleRefsJSON, err := json.Marshal(ruleRefs)
if err != nil {
return err
}
// set
setResult, err := db.Exec("INSERT INTO edgeHTTPFirewallRuleSets (isOn, code, name, rules, connector, state, actions) VALUES (1, ?, ?, ?, 'or', 1, ?)", setCode, setName, ruleRefsJSON, actionsJSON)
if err != nil {
return err
}
setId, err := setResult.LastInsertId()
if err != nil {
return err
}
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{
{
IsOn: true,
SetId: setId,
},
}
setRefsJSON, err := json.Marshal(setRefs)
if err != nil {
return err
}
// group
_, err = db.Exec("UPDATE edgeHTTPFirewallRuleGroups SET sets=? WHERE id=?", setRefsJSON, groupId)
if err != nil {
return err
}
return nil
}
// sql injection
{
ruleGroups, _, err := db.FindOnes("SELECT id, sets FROM edgeHTTPFirewallRuleGroups WHERE code='sqlInjection' AND state=1")
if err != nil {
return err
}
for _, ruleGroup := range ruleGroups {
var setsJSON = ruleGroup.GetBytes("sets")
if len(setsJSON) == 0 {
continue
}
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
err = json.Unmarshal(setsJSON, &setRefs)
if err != nil {
continue
}
if len(setRefs) != 5 {
continue
}
var isChanged = false
for setIndex, setRef := range setRefs {
set, setErr := db.FindOne("SELECT id, rules, isOn, actions FROM edgeHTTPFirewallRuleSets WHERE id=? AND state=1", setRef.SetId)
if setErr != nil {
return setErr
}
if set == nil {
isChanged = true
break
}
var rulesJSON = set.GetBytes("rules")
if len(rulesJSON) == 0 {
isChanged = true
break
}
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal(rulesJSON, &ruleRefs)
if err != nil {
return err
}
if len(ruleRefs) < 1 {
isChanged = true
break
}
var actionsJSON = set.GetBytes("actions")
if len(actionsJSON) == 0 {
isChanged = true
break
}
var actions = []*firewallconfigs.HTTPFirewallActionConfig{}
err = json.Unmarshal(actionsJSON, &actions)
if err != nil {
return err
}
if !(len(actions) == 1 && actions[0].Code == firewallconfigs.HTTPFirewallActionBlock) {
isChanged = true
break
}
var rules = []maps.Map{}
for _, ruleRef := range ruleRefs {
rule, ruleErr := db.FindOne("SELECT * FROM edgeHTTPFirewallRules WHERE id=? AND state=1", ruleRef.RuleId)
if ruleErr != nil {
return ruleErr
}
if rule == nil {
isChanged = true
break
}
rules = append(rules, rule)
}
if isChanged {
break
}
if len(rules) < 1 {
isChanged = true
break
}
switch setIndex {
case 0:
var rule = rules[0]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `union[\s/\*]+select`) {
isChanged = true
}
case 1:
var rule = rules[0]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `/\*(!|\x00)`) {
isChanged = true
}
case 2:
if len(rules) != 4 {
isChanged = true
} else {
{
var rule = rules[0]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s(and|or|rlike)\s+(if|updatexml)\s*\(`) {
isChanged = true
}
}
{
var rule = rules[1]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s+(and|or|rlike)\s+(select|case)\s+`) {
isChanged = true
}
}
{
var rule = rules[2]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s+(and|or|procedure)\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+(\s|$|--|#)`) {
isChanged = true
}
}
{
var rule = rules[3]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\(\s*case\s+when\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+\s+then\s+`) {
isChanged = true
}
}
}
case 3:
var rule = rules[0]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\b(updatexml|extractvalue|ascii|ord|char|chr|count|concat|rand|floor|substr|length|len|user|database|benchmark|analyse)\s*\(.*\)`) {
isChanged = true
}
case 4:
var rule = rules[0]
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `;\s*(declare|use|drop|create|exec|delete|update|insert)\s`) {
isChanged = true
}
}
}
if isChanged {
continue
}
for _, setRef := range setRefs {
err = disableSet(setRef.SetId)
if err != nil {
return err
}
}
err = addRuleToGroup(ruleGroup.GetInt64("id"), "7010", "SQL注入检测", []*firewallconfigs.HTTPFirewallActionConfig{
{
Code: firewallconfigs.HTTPFirewallActionPage,
Options: maps.Map{"status": 403, "body": ""},
},
}, "${requestAll}", firewallconfigs.HTTPFirewallRuleOperatorContainsSQLInjection, "")
if err != nil {
return err
}
}
}
// xss
{
ruleGroups, _, err := db.FindOnes("SELECT id, sets FROM edgeHTTPFirewallRuleGroups WHERE code='xss' AND state=1")
if err != nil {
return err
}
for _, ruleGroup := range ruleGroups {
var setsJSON = ruleGroup.GetBytes("sets")
if len(setsJSON) == 0 {
continue
}
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
err = json.Unmarshal(setsJSON, &setRefs)
if err != nil {
continue
}
if len(setRefs) != 3 {
continue
}
var isChanged = false
for setIndex, setRef := range setRefs {
set, setErr := db.FindOne("SELECT id, rules, isOn, actions FROM edgeHTTPFirewallRuleSets WHERE id=? AND state=1", setRef.SetId)
if setErr != nil {
return setErr
}
if set == nil {
isChanged = true
break
}
var rulesJSON = set.GetBytes("rules")
if len(rulesJSON) == 0 {
isChanged = true
break
}
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal(rulesJSON, &ruleRefs)
if err != nil {
return err
}
if len(ruleRefs) != 1 {
isChanged = true
break
}
var actionsJSON = set.GetBytes("actions")
if len(actionsJSON) == 0 {
isChanged = true
break
}
var actions = []*firewallconfigs.HTTPFirewallActionConfig{}
err = json.Unmarshal(actionsJSON, &actions)
if err != nil {
return err
}
if !(len(actions) == 1 && actions[0].Code == firewallconfigs.HTTPFirewallActionBlock) {
isChanged = true
break
}
rule, ruleErr := db.FindOne("SELECT * FROM edgeHTTPFirewallRules WHERE id=? AND state=1", ruleRefs[0].RuleId)
if ruleErr != nil {
return ruleErr
}
if rule == nil {
isChanged = true
break
}
switch setIndex {
case 0:
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `(onmouseover|onmousemove|onmousedown|onmouseup|onerror|onload|onclick|ondblclick|onkeydown|onkeyup|onkeypress)\s*=`) {
isChanged = true
}
case 1:
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `(alert|eval|prompt|confirm)\s*\(`) {
isChanged = true
}
case 2:
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `<(script|iframe|link)`) {
isChanged = true
}
}
}
if isChanged {
continue
}
for _, setRef := range setRefs {
err = disableSet(setRef.SetId)
if err != nil {
return err
}
}
err = addRuleToGroup(ruleGroup.GetInt64("id"), "1010", "XSS攻击检测", []*firewallconfigs.HTTPFirewallActionConfig{
{
Code: firewallconfigs.HTTPFirewallActionPage,
Options: maps.Map{"status": 403, "body": ""},
},
}, "${requestAll}", firewallconfigs.HTTPFirewallRuleOperatorContainsXSS, "")
if err != nil {
return err
}
}
}
}
// user register config
var newAddedFeatureCodes = []string{
userconfigs.UserFeatureCodeServerOptimization,
userconfigs.UserFeatureCodeServerAuth,
userconfigs.UserFeatureCodeServerWebsocket,
userconfigs.UserFeatureCodeServerHTTP3,
userconfigs.UserFeatureCodeServerCC,
userconfigs.UserFeatureCodeServerReferers,
userconfigs.UserFeatureCodeServerUserAgent,
userconfigs.UserFeatureCodeServerRequestLimit,
userconfigs.UserFeatureCodeServerCompression,
userconfigs.UserFeatureCodeServerRewriteRules,
userconfigs.UserFeatureCodeServerHostRedirects,
userconfigs.UserFeatureCodeServerHTTPHeaders,
userconfigs.UserFeatureCodeServerPages,
}
{
value, err := db.FindCol(0, "SELECT value FROM edgeSysSettings WHERE code=?", systemconfigs.SettingCodeUserRegisterConfig)
if err != nil {
return err
}
if value != nil {
var valueString = types.String(value)
if valueString != "null" && len(valueString) > 0 {
var registerConfig = &userconfigs.UserRegisterConfig{}
err = json.Unmarshal([]byte(valueString), registerConfig)
if err != nil {
return err
}
if len(registerConfig.Features) > 0 {
var newFeatureCodes = registerConfig.Features
var changed = false
for _, featureCode := range newAddedFeatureCodes {
if !lists.ContainsString(newFeatureCodes, featureCode) {
newFeatureCodes = append(newFeatureCodes, featureCode)
changed = true
}
}
if changed {
registerConfig.Features = newFeatureCodes
registerConfigJSON, err := json.Marshal(registerConfig)
if err != nil {
return err
}
_, err = db.Exec("UPDATE edgeSysSettings SET value=? WHERE code=?", registerConfigJSON, systemconfigs.SettingCodeUserRegisterConfig)
if err != nil {
return err
}
}
}
}
}
}
// user features
{
var sqlPieces []string
for _, featureCode := range newAddedFeatureCodes {
if strings.Contains(featureCode, "'") {
continue
}
sqlPieces = append(sqlPieces, "'$', '"+featureCode+"'")
}
_, err := db.Exec("UPDATE edgeUsers SET features=JSON_ARRAY_APPEND(features," + strings.Join(sqlPieces, ",") + ") WHERE features IS NOT NULL AND JSON_LENGTH(features)>0 AND NOT JSON_CONTAINS(features, '" + strconv.Quote(newAddedFeatureCodes[0]) + "')")
if err != nil {
return err
}
}
return nil
}

View File

@@ -289,3 +289,23 @@ func TestUpgradeSQLData_v1_2_10(t *testing.T) {
}
t.Log("ok")
}
func TestUpgradeSQLData_v1_3_2(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_3_2(db)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -33,7 +33,7 @@ func TestZero_Map(t *testing.T) {
var stat2 = &runtime.MemStats{}
runtime.ReadMemStats(stat2)
t.Log((stat2.HeapInuse-stat1.HeapInuse)/1024/1024, "MB")
t.Log((stat2.HeapInuse-stat1.HeapInuse)/1024/1024, "MiB")
t.Log(len(m))
_, ok := m[1024]