Compare commits

...

98 Commits

Author SHA1 Message Date
刘祥超
9d2ecf6822 提供用户某日刷新/预热缓存数量查询API 2023-05-28 18:00:51 +08:00
刘祥超
1a6d160a33 优化创建缓存任务时域名检查速度 2023-05-28 17:44:27 +08:00
刘祥超
b69132e1ca 版本号改为1.1.0 2023-05-28 16:06:53 +08:00
刘祥超
19890c209f 优化健康检查代码 2023-05-28 15:13:15 +08:00
刘祥超
1534436435 ACMETaskService.FindEnabledACMETask()返回信息中增加关联的证书信息 2023-05-25 14:55:46 +08:00
刘祥超
c087d1cba2 Update sql.json 2023-05-25 14:55:09 +08:00
刘祥超
cfc2ec5e4b 优化代码 2023-05-23 19:50:28 +08:00
刘祥超
af9c8523e9 实现集群CC防护策略设置 2023-05-23 19:16:30 +08:00
刘祥超
00977cf33e 实现集群自定义页面 2023-05-22 17:30:33 +08:00
刘祥超
fc2d018207 优化自定义页面配置存储 2023-05-22 10:04:46 +08:00
刘祥超
8569eebfee 修复使用localhost连接数据库时不能自动尝试启动的问题 2023-05-20 16:58:14 +08:00
刘祥超
73d72f0d33 HTTP Header中支持设置非标Header 2023-05-19 19:54:10 +08:00
刘祥超
c4b8540171 HTTP Header - CORS跨域设置增加多个选项 2023-05-19 16:34:24 +08:00
刘祥超
85219ac2ef 增加复制节点动作API 2023-05-19 11:12:24 +08:00
刘祥超
6976454bde 实现基础的智能调度 2023-05-17 18:42:21 +08:00
刘祥超
813ce44ceb 修复AscPk()写成Asc()的问题 2023-05-12 15:34:18 +08:00
刘祥超
294b57ca60 非超级用户不提示弱密码管理员 2023-05-06 14:04:21 +08:00
刘祥超
22010190b2 智能 DNS实现健康检查 2023-05-03 17:09:55 +08:00
刘祥超
cc4cd9c620 防盗链增加”同时检查Origin选项“ 2023-05-02 17:11:22 +08:00
刘祥超
5df9c0f1fd 检查节点认证时增加状态参数 2023-04-26 11:26:42 +08:00
刘祥超
dc3594a08d 集群健康检查可以同时检查单节点的多个IP 2023-04-26 10:50:29 +08:00
刘祥超
49ba1336cd 修复用户可能无法删除IP的问题 2023-04-25 11:28:04 +08:00
刘祥超
96db5af237 修复用户端无法查看IP名单的Bug 2023-04-25 11:18:09 +08:00
刘祥超
476ff91bf8 版本号修改为1.0.4 2023-04-24 10:18:26 +08:00
刘祥超
ac6b10489e DNSPod支持自定义线路分组 2023-04-24 09:37:26 +08:00
刘祥超
9352e1837f 创建初始化用户 2023-04-23 20:13:55 +08:00
刘祥超
ddec102d18 远程升级API节点时自动上传边缘节点安装文件 2023-04-23 19:42:51 +08:00
刘祥超
0d50b9b0cc 创建ACME用户、ACME任务时可以指定平台用户 2023-04-23 15:00:13 +08:00
刘祥超
20b4b47eea 优化edgeIPItems索引 2023-04-23 09:44:06 +08:00
刘祥超
ee8396c760 修复在节点列表中不能同时使用关键词和排序的问题 2023-04-21 15:27:24 +08:00
刘祥超
c3fa6a753a 修复只有一个泛域名时无法查询匹配证书的问题 2023-04-21 10:41:20 +08:00
刘祥超
fbe4de2e94 节点版本号修改为1.1.0 2023-04-19 21:02:01 +08:00
刘祥超
f5c7108799 IP库查询提供更多信息 2023-04-19 20:36:48 +08:00
刘祥超
5825a7e654 修复一处访问日志可能无法正确获得对应日期的问题 2023-04-18 17:54:01 +08:00
刘祥超
a6911117af 优化可用内存检查 2023-04-11 18:52:43 +08:00
刘祥超
b428db4f5e 版本号改为1.1.0 2023-04-10 21:03:31 +08:00
刘祥超
e4145a2059 优化启动速度 2023-04-10 20:57:38 +08:00
刘祥超
af13357985 创建缓存任务接口增加参数校验 2023-04-10 17:13:20 +08:00
刘祥超
1b949bd056 版本号修改为1.0.1 2023-04-10 09:18:12 +08:00
刘祥超
c4e415a72f 修复一个单词拼写错误/如果创建服务时没有指定服务名,则自动取第一个域名作为服务名 2023-04-09 20:11:36 +08:00
刘祥超
39cb95184d 查询弱密码管理员时只查询已启用的管理员 2023-04-09 17:31:09 +08:00
刘祥超
a7abca6c09 Update sql.json 2023-04-09 17:23:37 +08:00
刘祥超
894eff89ba 去除不需要的接口 2023-04-09 17:04:32 +08:00
刘祥超
35558f1d38 版本号更改为1.0.0 2023-04-09 16:19:52 +08:00
刘祥超
5a93ec0e32 增加服务之间拷贝配置的API(开源版本只有定义,没有完全实现) 2023-04-09 16:01:23 +08:00
刘祥超
73164de93e 查询快过期证书时,只查询启用的 2023-04-08 09:15:03 +08:00
刘祥超
199349084e 提供批量更新服务配置API(阶段性提交) 2023-04-06 20:49:22 +08:00
刘祥超
648fc2cac3 审计日志列表增加级别筛选 2023-04-06 10:06:56 +08:00
刘祥超
43f34950f3 自动检查管理员弱密码并提醒 2023-04-04 17:26:08 +08:00
刘祥超
1f0182e4a5 优化错误提示 2023-04-04 15:56:44 +08:00
刘祥超
3f972571b0 5秒盾策略变化时只更新策略配置 2023-04-03 16:11:48 +08:00
刘祥超
0618ca9f8a 优化操作IP条目时检查用户ID的相关代码 2023-04-03 10:02:17 +08:00
刘祥超
efd0823b25 上传SQL 2023-04-01 21:46:54 +08:00
刘祥超
af5ca9faf5 修复删除IP名单中IP时状态设置错误的问题 2023-04-01 20:48:47 +08:00
刘祥超
87c5eeb829 可以批量上传IP名单 2023-03-31 21:42:15 +08:00
刘祥超
df775272be 提供修改网站名称的接口 2023-03-31 15:30:22 +08:00
刘祥超
dbeabe4379 节点中增加授权信息 2023-03-31 12:39:01 +08:00
刘祥超
dd33504416 IP库文件可以加密 2023-03-30 20:00:22 +08:00
刘祥超
d45dca4edb IP制品列表中增加文件尺寸 2023-03-29 20:09:00 +08:00
刘祥超
b4472271ce 优化证书到期提醒等相关消息 2023-03-28 16:52:04 +08:00
刘祥超
138eddf771 修复发送站内消息时将标题作为内容的Bug 2023-03-28 16:25:18 +08:00
刘祥超
f0667abe55 删除edgeServers表中的state索引,防止查询时产生索引冲突 2023-03-27 17:14:48 +08:00
刘祥超
873af38807 优化服务列表查询 2023-03-27 17:14:12 +08:00
刘祥超
9bf46af088 增加默认CC设置 2023-03-26 12:41:01 +08:00
刘祥超
3a3b5bca20 上传单个证书时也可以选择所属用户 2023-03-26 12:24:31 +08:00
刘祥超
4806025f89 实现自动匹配证书和批量选择证书功能 2023-03-25 20:51:08 +08:00
刘祥超
d7c757a2a1 增加批量上传证书接口、使用域名查询证书接口 2023-03-24 19:07:43 +08:00
刘祥超
3e8873d828 修复查看服务24小时流量统计会产生panic的问题 2023-03-23 15:45:03 +08:00
刘祥超
84484b6538 优化服务带宽查询速度 2023-03-23 11:23:16 +08:00
刘祥超
d36e9e80ee 上传流量数据时同时上传服务所属用户ID 2023-03-22 19:33:25 +08:00
刘祥超
1fb831ca58 修复测试用例 2023-03-22 19:10:52 +08:00
刘祥超
5e20553602 合并部分流量查询和带宽查询 2023-03-22 17:54:44 +08:00
刘祥超
0f83d8ec66 导出SQL结构时使用embed取代生成sql.go 2023-03-22 11:19:58 +08:00
刘祥超
e45a6cbcb5 优化域名查询程序 2023-03-21 11:38:20 +08:00
刘祥超
ba1fd07555 增加edge-api token --role=[admin|user|api]命令用来快速查询节点Token 2023-03-19 21:24:24 +08:00
刘祥超
a70b4bfaf3 更新相关库 2023-03-19 17:51:21 +08:00
刘祥超
9cf47ae1af DNS集群增加自动检测端口选项 2023-03-19 17:44:56 +08:00
刘祥超
7f58d65a57 修复DataMap无法在多个节点之间共享的问题 2023-03-19 10:26:05 +08:00
刘祥超
4d40dd03de 优化节点压缩程序 2023-03-18 22:44:23 +08:00
刘祥超
e3ce79c9fc 增加RPC消息最大尺寸到512MB 2023-03-18 22:44:04 +08:00
刘祥超
f543edac1a 节点组合配置时服务间可以共用证书数据 2023-03-18 22:18:13 +08:00
刘祥超
1ce11a5745 优化服务配置组合 2023-03-18 19:52:42 +08:00
刘祥超
ab56c7451a DNS解析发生变化时立即触发同步任务 2023-03-18 16:53:08 +08:00
刘祥超
9800bbb661 修复无法同时对相同对象执行多次DNS解析任务的问题 2023-03-18 16:40:00 +08:00
刘祥超
8c4d2e7301 查询节点DNS信息时可以区分节点是否已安装 2023-03-18 16:05:10 +08:00
刘祥超
2c17675b6a 增加分隔关键词函数 2023-03-18 11:10:44 +08:00
刘祥超
3b30705f33 在API节点启动时,如果无法连接到本地MySQL数据库,则尝试启动固定位置上的MySQL 2023-03-17 16:02:37 +08:00
刘祥超
4cd9c5071d 版本号更改为0.6.5 2023-03-17 15:53:52 +08:00
刘祥超
763a72d526 版本号变更为0.6.4.2 2023-03-16 08:59:59 +08:00
刘祥超
bd762ad10b 读取节点列表时可以按照连接数排序 2023-03-15 17:57:49 +08:00
刘祥超
56574ea3d9 节点看板数据中增加当月、昨日、今日流量 2023-03-15 17:02:09 +08:00
刘祥超
6a31605519 集群看板数据中增加当月流量 2023-03-15 16:24:36 +08:00
刘祥超
c7abeeaf07 优化代码 2023-03-14 09:17:05 +08:00
刘祥超
c11483ec6d 允许API之间相互调用 2023-03-13 16:15:31 +08:00
刘祥超
c3713cefc9 生成数据库结构sql.go文件的同时生成sql.json 2023-03-13 14:32:39 +08:00
刘祥超
2098bd4d32 版本号改为0.6.5 2023-03-13 14:29:34 +08:00
刘祥超
7a6a02284e 修复搜索引擎IP库可能无法升级的Bug 2023-03-13 10:36:41 +08:00
刘祥超
c749a7b088 版本号改为0.6.4.1 2023-03-13 10:36:03 +08:00
151 changed files with 197729 additions and 968 deletions

View File

@@ -12,4 +12,5 @@ dbs:
fields: fields:
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables" ] bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified" ]

View File

@@ -17,6 +17,7 @@ import (
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"log" "log"
"os" "os"
"strings"
) )
func main() { func main() {
@@ -188,6 +189,38 @@ func main() {
} }
} }
}) })
app.On("token", func() {
var role = ""
if len(os.Args) <= 2 {
fmt.Println("require --role parameter")
return
}
var set = flag.NewFlagSet("", flag.ExitOnError)
set.StringVar(&role, "role", "", "edge-api token --role=[admin|user|api]")
_ = set.Parse(os.Args[2:])
var sock = gosock.NewTmpSock(teaconst.ProcessName)
reply, err := sock.Send(&gosock.Command{Code: "lookupToken", Params: map[string]any{
"role": role,
}})
if err != nil {
fmt.Println("[ERROR]" + err.Error())
} else {
var resultMap = maps.NewMap(reply.Params)
if resultMap.GetBool("isOk") {
var tokens = resultMap.GetSlice("tokens")
fmt.Printf("%-35s | %-35s\n", "nodeId", "secret")
fmt.Println(strings.Repeat("-", 70))
for _, tokenMap := range tokens {
var m = maps.NewMap(tokenMap)
fmt.Printf("%-35s | %-35s\n", m.GetString("nodeId"), m.GetString("secret"))
}
} else {
fmt.Println("[ERROR]" + resultMap.GetString("err"))
}
}
})
app.Run(func() { app.Run(func() {
nodes.NewAPINode().Start() nodes.NewAPINode().Start()

View File

@@ -4,12 +4,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAPI/internal/setup" "github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"go/format"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
) )
func main() { func main() {
@@ -23,53 +22,20 @@ func main() {
fmt.Println("[ERROR]" + err.Error()) fmt.Println("[ERROR]" + err.Error())
return return
} }
resultsJSON, err := json.Marshal(results)
prettyResultsJSON, err := json.MarshalIndent(results, "", " ")
if err != nil { if err != nil {
fmt.Println("[ERROR]" + err.Error()) fmt.Println("[ERROR]" + err.Error())
return return
} }
dir, _ := os.Getwd()
var sqlFile string
for i := 0; i < 5; i++ {
lookupFile := dir + "/internal/setup/sql.go"
_, err = os.Stat(lookupFile)
if err != nil {
dir = filepath.Dir(dir)
continue
}
sqlFile = lookupFile
}
if len(sqlFile) == 0 { // 写入到 sql.json 中
fmt.Println("[ERROR]can not find sql.go") var dir = filepath.Dir(Tea.Root)
return err = os.WriteFile(dir+"/internal/setup/sql.json", prettyResultsJSON, 0666)
}
content := []byte(`package setup
import (
"encoding/json"
"github.com/iwind/TeaGo/logs"
)
// 最新版本的数据库SQL语句用来对比并升级已有的数据库
// 由 sql-dump/main.go 自动生成
func init() {
err := json.Unmarshal([]byte(` + strconv.Quote(string(resultsJSON)) + `), LatestSQLResult)
if err != nil { if err != nil {
logs.Println("[ERROR]load sql failed: " + err.Error()) fmt.Println("[ERROR]" + err.Error())
}
}
`)
dst, err := format.Source(content)
if err != nil {
fmt.Println("[ERROR]format code failed: " + err.Error())
return return
} }
err = os.WriteFile(sqlFile, dst, 0666)
if err != nil {
fmt.Println("[ERROR]write file failed: " + err.Error())
return
}
fmt.Println("ok") fmt.Println("ok")
} }

12
go.mod
View File

@@ -11,7 +11,7 @@ require (
github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1 github.com/cespare/xxhash/v2 v2.1.1
github.com/go-acme/lego/v4 v4.9.0 github.com/go-acme/lego/v4 v4.9.0
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.7.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
@@ -21,8 +21,8 @@ require (
github.com/shirou/gopsutil/v3 v3.22.2 github.com/shirou/gopsutil/v3 v3.22.2
github.com/smartwalle/alipay/v3 v3.1.7 github.com/smartwalle/alipay/v3 v3.1.7
golang.org/x/crypto v0.1.0 golang.org/x/crypto v0.1.0
golang.org/x/net v0.7.0 golang.org/x/net v0.8.0
golang.org/x/sys v0.5.0 golang.org/x/sys v0.6.0
google.golang.org/grpc v1.45.0 google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@@ -44,9 +44,9 @@ require (
github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
google.golang.org/protobuf v1.28.0 // indirect google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/ini.v1 v1.66.6 // indirect

31
go.sum
View File

@@ -43,8 +43,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g= github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
@@ -78,10 +79,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc= github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20230109112127-225731e65eea h1:e5jlcUN13pNzUbyNW8Ag2Ev5K/2ppgY0m5grqTeFI6Q=
github.com/iwind/TeaGo v0.0.0-20230109112127-225731e65eea/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20230303070415-9d0689db6456 h1:xv3AVaxuwjThkBDptAfsFSmuHQIrRrvt8BRaekWnsvs=
github.com/iwind/TeaGo v0.0.0-20230303070415-9d0689db6456/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 h1:TuRxvKRv9PxKVijWOkUnZm5TeanQqWGUJyPx9u6cra4= github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 h1:TuRxvKRv9PxKVijWOkUnZm5TeanQqWGUJyPx9u6cra4=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s= github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo= github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo=
@@ -179,8 +176,8 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -194,8 +191,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -203,7 +200,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -225,17 +222,17 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -244,8 +241,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

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

View File

@@ -7,13 +7,29 @@ import (
"fmt" "fmt"
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"os"
"strings"
"time" "time"
) )
var ( var (
IsPlus = false IsPlus = false
Edition = ""
MaxNodes int32 = 0 MaxNodes int32 = 0
NodeId int64 = 0 NodeId int64 = 0
Debug = false Debug = false
InstanceCode = fmt.Sprintf("%x", sha1.Sum([]byte("INSTANCE"+types.String(time.Now().UnixNano())+"@"+types.String(rands.Int64())))) InstanceCode = fmt.Sprintf("%x", sha1.Sum([]byte("INSTANCE"+types.String(time.Now().UnixNano())+"@"+types.String(rands.Int64()))))
IsMain = checkMain()
) )
// 检查是否为主程序
func checkMain() bool {
if len(os.Args) == 1 ||
(len(os.Args) >= 2 && os.Args[1] == "pprof") {
return true
}
exe, _ := os.Executable()
return strings.HasSuffix(exe, ".test") ||
strings.HasSuffix(exe, ".test.exe") ||
strings.Contains(exe, "___")
}

View File

@@ -434,7 +434,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
CertData: certData, CertData: certData,
KeyData: keyData, KeyData: keyData,
} }
err = sslConfig.Init() err = sslConfig.Init(nil)
if err != nil { if err != nil {
errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error() errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error()
return return

View File

@@ -131,6 +131,8 @@ func (this *ACMEUserDAO) CountACMEUsersWithAdminId(tx *dbs.Tx, adminId int64, us
} }
if userId > 0 { if userId > 0 {
query.Attr("userId", userId) query.Attr("userId", userId)
} else {
query.Attr("userId", 0)
} }
if accountId > 0 { if accountId > 0 {
query.Attr("accountId", accountId) query.Attr("accountId", accountId)
@@ -149,6 +151,8 @@ func (this *ACMEUserDAO) ListACMEUsers(tx *dbs.Tx, adminId int64, userId int64,
} }
if userId > 0 { if userId > 0 {
query.Attr("userId", userId) query.Attr("userId", userId)
} else {
query.Attr("userId", 0)
} }
_, err = query. _, err = query.

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
@@ -266,17 +267,36 @@ func (this *AdminDAO) FindAllAdminModules(tx *dbs.Tx) (result []*Admin, err erro
} }
// CountAllEnabledAdmins 计算所有管理员数量 // CountAllEnabledAdmins 计算所有管理员数量
func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx) (int64, error) { func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool) (int64, error) {
return this.Query(tx). var query = this.Query(tx)
if len(keyword) > 0 {
query.Where("(username LIKE :keyword OR fullname LIKE :keyword)")
query.Param("keyword", dbutils.QuoteLike(keyword))
}
if hasWeakPasswords {
query.Attr("password", weakPasswords)
query.Attr("isOn", true)
}
return query.
State(AdminStateEnabled). State(AdminStateEnabled).
Count() Count()
} }
// ListEnabledAdmins 列出单页的管理员 // ListEnabledAdmins 列出单页的管理员
func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, offset int64, size int64) (result []*Admin, err error) { func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool, offset int64, size int64) (result []*Admin, err error) {
_, err = this.Query(tx). var query = this.Query(tx)
if len(keyword) > 0 {
query.Where("(username LIKE :keyword OR fullname LIKE :keyword)")
query.Param("keyword", dbutils.QuoteLike(keyword))
}
if hasWeakPasswords {
query.Attr("password", weakPasswords)
query.Attr("isOn", true)
}
_, err = query.
State(AdminStateEnabled). State(AdminStateEnabled).
Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin"). Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin", "password").
Offset(offset). Offset(offset).
Limit(size). Limit(size).
DescPk(). DescPk().
@@ -292,3 +312,15 @@ func (this *AdminDAO) UpdateAdminTheme(tx *dbs.Tx, adminId int64, theme string)
Set("theme", theme). Set("theme", theme).
UpdateQuickly() UpdateQuickly()
} }
// CheckSuperAdmin 检查管理员是否为超级管理员
func (this *AdminDAO) CheckSuperAdmin(tx *dbs.Tx, adminId int64) (bool, error) {
if adminId <= 0 {
return false, nil
}
return this.Query(tx).
Pk(adminId).
State(AdminStateEnabled).
Attr("isSuper", true).
Exist()
}

View File

@@ -1 +1,42 @@
package models package models
import stringutil "github.com/iwind/TeaGo/utils/string"
// 弱密码集合
var weakPasswords = []string{}
func init() {
// 初始化弱密码集合
for _, password := range []string{
"123",
"1234",
"12345",
"123456",
"12345678",
"123456789",
"000000",
"111111",
"666666",
"888888",
"654321",
"123456789",
"password",
"qwerty",
"admin",
} {
weakPasswords = append(weakPasswords, stringutil.Md5(password))
}
}
func (this *Admin) HasWeakPassword() bool {
if len(this.Password) == 0 {
return false
}
for _, weakPassword := range weakPasswords {
if weakPassword == this.Password {
return true
}
}
return false
}

View File

@@ -37,7 +37,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
return nil, err return nil, err
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -45,7 +45,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
if config.SSLPolicyRef != nil { if config.SSLPolicyRef != nil {
var policyId = config.SSLPolicyRef.SSLPolicyId var policyId = config.SSLPolicyRef.SSLPolicyId
if policyId > 0 { if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap) sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -55,7 +55,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
} }
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -129,13 +129,13 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if !IsNotNull(this.RestHTTPS) { if !IsNotNull(this.RestHTTPS) {
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPSProtocolConfig{} var config = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(this.RestHTTPS, config) err := json.Unmarshal(this.RestHTTPS, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -143,7 +143,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if config.SSLPolicyRef != nil { if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 { if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap) sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -153,7 +153,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
} }
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -12,13 +12,16 @@ import (
type DNSTaskType = string type DNSTaskType = string
const ( const (
DNSTaskTypeClusterChange DNSTaskType = "clusterChange" DNSTaskTypeClusterChange DNSTaskType = "clusterChange" // 集群节点、服务发生变化
DNSTaskTypeClusterNodesChange DNSTaskType = "clusterNodesChange" // 集群中节点发生变化
DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名 DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
DNSTaskTypeNodeChange DNSTaskType = "nodeChange" DNSTaskTypeNodeChange DNSTaskType = "nodeChange"
DNSTaskTypeServerChange DNSTaskType = "serverChange" DNSTaskTypeServerChange DNSTaskType = "serverChange"
DNSTaskTypeDomainChange DNSTaskType = "domainChange" DNSTaskTypeDomainChange DNSTaskType = "domainChange"
) )
var DNSTasksNotifier = make(chan bool, 2)
type DNSTaskDAO dbs.DAO type DNSTaskDAO dbs.DAO
func NewDNSTaskDAO() *DNSTaskDAO { func NewDNSTaskDAO() *DNSTaskDAO {
@@ -64,7 +67,17 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
"error": "", "error": "",
"version": time.Now().UnixNano(), "version": time.Now().UnixNano(),
}) })
return err if err != nil {
return err
}
// 通知更新
select {
case DNSTasksNotifier <- true:
default:
}
return nil
} }
// CreateClusterTask 生成集群变更任务 // CreateClusterTask 生成集群变更任务
@@ -156,10 +169,24 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
} }
// UpdateDNSTaskDone 设置任务完成 // UpdateDNSTaskDone 设置任务完成
func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64) error { func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64, taskVersion int64) error {
if taskId <= 0 { if taskId <= 0 {
return errors.New("invalid taskId") return errors.New("invalid taskId")
} }
currentVersion, err := this.Query(tx).
Pk(taskId).
Result("version").
FindInt64Col(0)
if err != nil {
return err
}
// 如果版本号发生变化,则说明有新的要执行的任务
if taskVersion > 0 && currentVersion > 0 && currentVersion != taskVersion {
return nil
}
var op = NewDNSTaskOperator() var op = NewDNSTaskOperator()
op.Id = taskId op.Id = taskId
op.IsDone = true op.IsDone = true

View File

@@ -105,7 +105,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
// 检查节点 // 检查节点
if checkNodeIssues { if checkNodeIssues {
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, clusterDNSConfig != nil && clusterDNSConfig.IncludingLnNodes) nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, clusterDNSConfig != nil && clusterDNSConfig.IncludingLnNodes, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -162,17 +162,36 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
return nil, err return nil, err
} }
if len(ipAddr) == 0 { if len(ipAddr) == 0 {
issues = append(issues, &pb.DNSIssue{ // 检查是否有离线
Target: node.Name, anyIPAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, false, nodeconfigs.NodeRoleNode)
TargetId: nodeId, if err != nil {
Type: "node", return nil, err
Description: "没有设置IP地址", }
Params: map[string]string{ if len(anyIPAddr) > 0 {
"clusterName": cluster.Name, issues = append(issues, &pb.DNSIssue{
"clusterId": numberutils.FormatInt64(clusterId), Target: node.Name,
}, TargetId: nodeId,
MustFix: true, Type: "node",
}) Description: "节点所有IP地址处于离线状态",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
} else {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "没有设置可用的IP地址",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
}
continue continue
} }

View File

@@ -237,7 +237,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
if len(accessLog.TimeISO8601) > 10 { if len(accessLog.TimeISO8601) > 10 {
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "") day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
} else { } else {
timeutil.FormatTime("Ymd", accessLog.Timestamp) day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
} }
tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true) tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true)

View File

@@ -96,6 +96,27 @@ func (this *HTTPAuthPolicyDAO) UpdateHTTPAuthPolicy(tx *dbs.Tx, policyId int64,
return this.NotifyUpdate(tx, policyId) return this.NotifyUpdate(tx, policyId)
} }
// CloneAuthPolicy 复制策略
func (this *HTTPAuthPolicyDAO) CloneAuthPolicy(tx *dbs.Tx, fromPolicyId int64) (int64, error) {
policyOne, err := this.Query(tx).
Pk(fromPolicyId).
Find()
if err != nil || policyOne == nil {
return 0, err
}
var policy = policyOne.(*HTTPAuthPolicy)
var op = NewHTTPAuthPolicyOperator()
op.IsOn = policy.IsOn
op.Name = policy.Name
op.Type = policy.Type
if len(policy.Params) > 0 {
op.Params = policy.Params
}
op.State = policy.State
return this.SaveInt64(tx, op)
}
// ComposePolicyConfig 组合配置 // ComposePolicyConfig 组合配置
func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPAuthPolicy, error) { func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPAuthPolicy, error) {
if cacheMap == nil { if cacheMap == nil {

View File

@@ -157,6 +157,9 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
return errors.New("invalid policyId") return errors.New("invalid policyId")
} }
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames) namesJSON, err := json.Marshal(headerNames)
if err != nil { if err != nil {
return err return err
@@ -164,7 +167,31 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
var op = NewHTTPHeaderPolicyOperator() var op = NewHTTPHeaderPolicyOperator()
op.Id = policyId op.Id = policyId
op.DeleteHeaders = string(namesJSON) op.DeleteHeaders = namesJSON
err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, policyId)
}
// UpdateNonStandardHeaders 修改非标Headers
func (this *HTTPHeaderPolicyDAO) UpdateNonStandardHeaders(tx *dbs.Tx, policyId int64, headerNames []string) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames)
if err != nil {
return err
}
var op = NewHTTPHeaderPolicyOperator()
op.Id = policyId
op.NonStandardHeaders = namesJSON
err = this.Save(tx, op) err = this.Save(tx, op)
if err != nil { if err != nil {
return err return err
@@ -220,9 +247,19 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
config.DeleteHeaders = headers config.DeleteHeaders = headers
} }
// Non-Standard Headers
if IsNotNull(policy.NonStandardHeaders) {
var headers = []string{}
err = json.Unmarshal(policy.NonStandardHeaders, &headers)
if err != nil {
return nil, err
}
config.NonStandardHeaders = headers
}
// CORS // CORS
if IsNotNull(policy.Cors) { if IsNotNull(policy.Cors) {
var corsConfig = &shared.HTTPCORSHeaderConfig{} var corsConfig = shared.NewHTTPCORSHeaderConfig()
err = json.Unmarshal(policy.Cors, corsConfig) err = json.Unmarshal(policy.Cors, corsConfig)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -4,35 +4,37 @@ import "github.com/iwind/TeaGo/dbs"
// HTTPHeaderPolicy Header定义 // HTTPHeaderPolicy Header定义
type HTTPHeaderPolicy struct { type HTTPHeaderPolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
AddHeaders dbs.JSON `field:"addHeaders"` // 添加的Header AddHeaders dbs.JSON `field:"addHeaders"` // 添加的Header
AddTrailers dbs.JSON `field:"addTrailers"` // 添加的Trailers AddTrailers dbs.JSON `field:"addTrailers"` // 添加的Trailers
SetHeaders dbs.JSON `field:"setHeaders"` // 设置Header SetHeaders dbs.JSON `field:"setHeaders"` // 设置Header
ReplaceHeaders dbs.JSON `field:"replaceHeaders"` // 替换Header内容 ReplaceHeaders dbs.JSON `field:"replaceHeaders"` // 替换Header内容
Expires dbs.JSON `field:"expires"` // Expires单独设置 Expires dbs.JSON `field:"expires"` // Expires单独设置
DeleteHeaders dbs.JSON `field:"deleteHeaders"` // 删除的Headers DeleteHeaders dbs.JSON `field:"deleteHeaders"` // 删除的Headers
Cors dbs.JSON `field:"cors"` // CORS配置 NonStandardHeaders dbs.JSON `field:"nonStandardHeaders"` // 非标Headers
Cors dbs.JSON `field:"cors"` // CORS配置
} }
type HTTPHeaderPolicyOperator struct { type HTTPHeaderPolicyOperator struct {
Id any // ID Id any // ID
IsOn any // 是否启用 IsOn any // 是否启用
State any // 状态 State any // 状态
AdminId any // 管理员ID AdminId any // 管理员ID
UserId any // 用户ID UserId any // 用户ID
CreatedAt any // 创建时间 CreatedAt any // 创建时间
AddHeaders any // 添加的Header AddHeaders any // 添加的Header
AddTrailers any // 添加的Trailers AddTrailers any // 添加的Trailers
SetHeaders any // 设置Header SetHeaders any // 设置Header
ReplaceHeaders any // 替换Header内容 ReplaceHeaders any // 替换Header内容
Expires any // Expires单独设置 Expires any // Expires单独设置
DeleteHeaders any // 删除的Headers DeleteHeaders any // 删除的Headers
Cors any // CORS配置 NonStandardHeaders any // 非标Headers
Cors any // CORS配置
} }
func NewHTTPHeaderPolicyOperator() *HTTPHeaderPolicyOperator { func NewHTTPHeaderPolicyOperator() *HTTPHeaderPolicyOperator {

View File

@@ -150,7 +150,7 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
} }
// ComposeLocationConfig 组合配置 // ComposeLocationConfig 组合配置
func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPLocationConfig, error) { func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.HTTPLocationConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -168,7 +168,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPLocationConfig{} var config = &serverconfigs.HTTPLocationConfig{}
config.Id = int64(location.Id) config.Id = int64(location.Id)
config.IsOn = location.IsOn config.IsOn = location.IsOn
config.Description = location.Description config.Description = location.Description
@@ -179,7 +179,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
// web // web
if location.WebId > 0 { if location.WebId > 0 {
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId), cacheMap) webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId), true, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -195,7 +195,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
} }
config.ReverseProxyRef = ref config.ReverseProxyRef = ref
if ref.ReverseProxyId > 0 { if ref.ReverseProxyId > 0 {
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -292,13 +292,13 @@ func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, web
} }
// ConvertLocationRefs 转换引用为配置 // ConvertLocationRefs 转换引用为配置
func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef, cacheMap *utils.CacheMap) (locations []*serverconfigs.HTTPLocationConfig, err error) { func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (locations []*serverconfigs.HTTPLocationConfig, err error) {
for _, ref := range refs { for _, ref := range refs {
config, err := this.ComposeLocationConfig(tx, ref.LocationId, cacheMap) config, err := this.ComposeLocationConfig(tx, ref.LocationId, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
children, err := this.ConvertLocationRefs(tx, ref.Children, cacheMap) children, err := this.ConvertLocationRefs(tx, ref.Children, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -133,6 +133,32 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
return this.NotifyUpdate(tx, pageId) return this.NotifyUpdate(tx, pageId)
} }
// ClonePage 克隆页面
func (this *HTTPPageDAO) ClonePage(tx *dbs.Tx, fromPageId int64) (newPageId int64, err error) {
if fromPageId <= 0 {
return
}
pageOne, err := this.Query(tx).
Pk(fromPageId).
Find()
if err != nil || pageOne == nil {
return 0, err
}
var page = pageOne.(*HTTPPage)
var op = NewHTTPPageOperator()
op.IsOn = page.IsOn
if len(page.StatusList) > 0 {
op.StatusList = page.StatusList
}
op.Url = page.Url
op.NewStatus = page.NewStatus
op.Body = page.Body
op.BodyType = page.BodyType
op.State = page.State
return this.SaveInt64(tx, op)
}
// ComposePageConfig 组合配置 // ComposePageConfig 组合配置
func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPPageConfig, error) { func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPPageConfig, error) {
if cacheMap == nil { if cacheMap == nil {

View File

@@ -77,7 +77,7 @@ func (this *HTTPWebDAO) FindEnabledHTTPWeb(tx *dbs.Tx, id int64) (*HTTPWeb, erro
} }
// ComposeWebConfig 组合配置 // ComposeWebConfig 组合配置
func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPWebConfig, error) { func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGroup bool, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.HTTPWebConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -101,113 +101,127 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// root // root
if IsNotNull(web.Root) { if IsNotNull(web.Root) {
rootConfig := &serverconfigs.HTTPRootConfig{} var rootConfig = &serverconfigs.HTTPRootConfig{}
err = json.Unmarshal(web.Root, rootConfig) err = json.Unmarshal(web.Root, rootConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Root = rootConfig if this.shouldCompose(isLocationOrGroup, forNode, rootConfig.IsPrior, rootConfig.IsOn) {
config.Root = rootConfig
}
} }
// compression // compression
if IsNotNull(web.Compression) { if IsNotNull(web.Compression) {
compression := &serverconfigs.HTTPCompressionConfig{} var compressionConfig = &serverconfigs.HTTPCompressionConfig{}
err = json.Unmarshal(web.Compression, compression) err = json.Unmarshal(web.Compression, compressionConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Compression = compression
// gzip if this.shouldCompose(isLocationOrGroup, forNode, compressionConfig.IsPrior, compressionConfig.IsOn) {
if compression.GzipRef != nil && compression.GzipRef.Id > 0 { config.Compression = compressionConfig
gzipConfig, err := SharedHTTPGzipDAO.ComposeGzipConfig(tx, compression.GzipRef.Id)
if err != nil {
return nil, err
}
compression.Gzip = gzipConfig
}
// brotli // gzip
if compression.BrotliRef != nil && compression.BrotliRef.Id > 0 { if compressionConfig.GzipRef != nil && compressionConfig.GzipRef.Id > 0 {
brotliConfig, err := SharedHTTPBrotliPolicyDAO.ComposeBrotliConfig(tx, compression.BrotliRef.Id) gzipConfig, err := SharedHTTPGzipDAO.ComposeGzipConfig(tx, compressionConfig.GzipRef.Id)
if err != nil { if err != nil {
return nil, err return nil, err
}
compressionConfig.Gzip = gzipConfig
} }
compression.Brotli = brotliConfig
}
// deflate // brotli
if compression.DeflateRef != nil && compression.DeflateRef.Id > 0 { if compressionConfig.BrotliRef != nil && compressionConfig.BrotliRef.Id > 0 {
deflateConfig, err := SharedHTTPDeflatePolicyDAO.ComposeDeflateConfig(tx, compression.DeflateRef.Id) brotliConfig, err := SharedHTTPBrotliPolicyDAO.ComposeBrotliConfig(tx, compressionConfig.BrotliRef.Id)
if err != nil { if err != nil {
return nil, err return nil, err
}
compressionConfig.Brotli = brotliConfig
}
// deflate
if compressionConfig.DeflateRef != nil && compressionConfig.DeflateRef.Id > 0 {
deflateConfig, err := SharedHTTPDeflatePolicyDAO.ComposeDeflateConfig(tx, compressionConfig.DeflateRef.Id)
if err != nil {
return nil, err
}
compressionConfig.Deflate = deflateConfig
} }
compression.Deflate = deflateConfig
} }
} }
// charset // charset
if IsNotNull(web.Charset) { if IsNotNull(web.Charset) {
charsetConfig := &serverconfigs.HTTPCharsetConfig{} var charsetConfig = &serverconfigs.HTTPCharsetConfig{}
err = json.Unmarshal(web.Charset, charsetConfig) err = json.Unmarshal(web.Charset, charsetConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Charset = charsetConfig if this.shouldCompose(isLocationOrGroup, forNode, charsetConfig.IsPrior, charsetConfig.IsOn) {
config.Charset = charsetConfig
}
} }
// headers // headers
if IsNotNull(web.RequestHeader) { if IsNotNull(web.RequestHeader) {
ref := &shared.HTTPHeaderPolicyRef{} var ref = &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal(web.RequestHeader, ref) err = json.Unmarshal(web.RequestHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RequestHeaderPolicyRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
config.RequestHeaderPolicyRef = ref
if ref.HeaderPolicyId > 0 { if ref.HeaderPolicyId > 0 {
headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId) headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if headerPolicy != nil { if headerPolicy != nil {
config.RequestHeaderPolicy = headerPolicy config.RequestHeaderPolicy = headerPolicy
}
} }
} }
} }
if IsNotNull(web.ResponseHeader) { if IsNotNull(web.ResponseHeader) {
ref := &shared.HTTPHeaderPolicyRef{} var ref = &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal(web.ResponseHeader, ref) err = json.Unmarshal(web.ResponseHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.ResponseHeaderPolicyRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
config.ResponseHeaderPolicyRef = ref
if ref.HeaderPolicyId > 0 { if ref.HeaderPolicyId > 0 {
headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId) headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if headerPolicy != nil { if headerPolicy != nil {
config.ResponseHeaderPolicy = headerPolicy config.ResponseHeaderPolicy = headerPolicy
}
} }
} }
} }
// shutdown // shutdown
if IsNotNull(web.Shutdown) { if IsNotNull(web.Shutdown) {
shutdownConfig := &serverconfigs.HTTPShutdownConfig{} var shutdownConfig = &serverconfigs.HTTPShutdownConfig{}
err = json.Unmarshal(web.Shutdown, shutdownConfig) err = json.Unmarshal(web.Shutdown, shutdownConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Shutdown = shutdownConfig if this.shouldCompose(isLocationOrGroup, forNode, shutdownConfig.IsPrior, shutdownConfig.IsOn) {
config.Shutdown = shutdownConfig
}
} }
// pages // pages
// TODO 检查forNode参数
if IsNotNull(web.Pages) { if IsNotNull(web.Pages) {
pages := []*serverconfigs.HTTPPageConfig{} var pages = []*serverconfigs.HTTPPageConfig{}
err = json.Unmarshal(web.Pages, &pages) err = json.Unmarshal(web.Pages, &pages)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -226,62 +240,72 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 访问日志 // 访问日志
if IsNotNull(web.AccessLog) { if IsNotNull(web.AccessLog) {
accessLogConfig := &serverconfigs.HTTPAccessLogRef{} var accessLogConfig = &serverconfigs.HTTPAccessLogRef{}
err = json.Unmarshal(web.AccessLog, accessLogConfig) err = json.Unmarshal(web.AccessLog, accessLogConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.AccessLogRef = accessLogConfig if this.shouldCompose(isLocationOrGroup, forNode, accessLogConfig.IsPrior, accessLogConfig.IsOn) {
config.AccessLogRef = accessLogConfig
}
} }
// 统计配置 // 统计配置
if IsNotNull(web.Stat) { if IsNotNull(web.Stat) {
statRef := &serverconfigs.HTTPStatRef{} var statRef = &serverconfigs.HTTPStatRef{}
err = json.Unmarshal(web.Stat, statRef) err = json.Unmarshal(web.Stat, statRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.StatRef = statRef if this.shouldCompose(isLocationOrGroup, forNode, statRef.IsPrior, statRef.IsOn) {
config.StatRef = statRef
}
} }
// 缓存配置 // 缓存配置
if IsNotNull(web.Cache) { if IsNotNull(web.Cache) {
cacheConfig := &serverconfigs.HTTPCacheConfig{} var cacheConfig = &serverconfigs.HTTPCacheConfig{}
err = json.Unmarshal(web.Cache, &cacheConfig) err = json.Unmarshal(web.Cache, &cacheConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Cache = cacheConfig
if this.shouldCompose(isLocationOrGroup, forNode, cacheConfig.IsPrior, cacheConfig.IsOn) {
config.Cache = cacheConfig
}
// 暂不支持自定义缓存策略设置,因为同一个集群下的服务需要集中管理 // 暂不支持自定义缓存策略设置,因为同一个集群下的服务需要集中管理
} }
// 防火墙配置 // 防火墙配置
if IsNotNull(web.Firewall) { if IsNotNull(web.Firewall) {
firewallRef := &firewallconfigs.HTTPFirewallRef{} var firewallRef = &firewallconfigs.HTTPFirewallRef{}
err = json.Unmarshal(web.Firewall, firewallRef) err = json.Unmarshal(web.Firewall, firewallRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.FirewallRef = firewallRef if this.shouldCompose(isLocationOrGroup, forNode, firewallRef.IsPrior, firewallRef.IsOn) {
config.FirewallRef = firewallRef
// 自定义防火墙设置 // 自定义防火墙设置
if firewallRef.FirewallPolicyId > 0 { if firewallRef.FirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap) firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if firewallPolicy == nil { if firewallPolicy == nil {
config.FirewallRef = nil config.FirewallRef = nil
} else { } else {
config.FirewallPolicy = firewallPolicy config.FirewallPolicy = firewallPolicy
}
} }
} }
} }
// 路由规则 // 路由规则
// TODO 检查forNode参数
if IsNotNull(web.Locations) { if IsNotNull(web.Locations) {
refs := []*serverconfigs.HTTPLocationRef{} var refs = []*serverconfigs.HTTPLocationRef{}
err = json.Unmarshal(web.Locations, &refs) err = json.Unmarshal(web.Locations, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -289,7 +313,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if len(refs) > 0 { if len(refs) > 0 {
config.LocationRefs = refs config.LocationRefs = refs
locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs, cacheMap) locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -299,36 +323,41 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 跳转 // 跳转
if IsNotNull(web.RedirectToHttps) { if IsNotNull(web.RedirectToHttps) {
redirectToHTTPSConfig := &serverconfigs.HTTPRedirectToHTTPSConfig{} var redirectToHTTPSConfig = &serverconfigs.HTTPRedirectToHTTPSConfig{}
err = json.Unmarshal(web.RedirectToHttps, redirectToHTTPSConfig) err = json.Unmarshal(web.RedirectToHttps, redirectToHTTPSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RedirectToHttps = redirectToHTTPSConfig if this.shouldCompose(isLocationOrGroup, forNode, redirectToHTTPSConfig.IsPrior, redirectToHTTPSConfig.IsOn) {
config.RedirectToHttps = redirectToHTTPSConfig
}
} }
// Websocket // Websocket
if IsNotNull(web.Websocket) { if IsNotNull(web.Websocket) {
ref := &serverconfigs.HTTPWebsocketRef{} var ref = &serverconfigs.HTTPWebsocketRef{}
err = json.Unmarshal(web.Websocket, ref) err = json.Unmarshal(web.Websocket, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.WebsocketRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
if ref.WebsocketId > 0 { config.WebsocketRef = ref
websocketConfig, err := SharedHTTPWebsocketDAO.ComposeWebsocketConfig(tx, ref.WebsocketId) if ref.WebsocketId > 0 {
if err != nil { websocketConfig, err := SharedHTTPWebsocketDAO.ComposeWebsocketConfig(tx, ref.WebsocketId)
return nil, err if err != nil {
} return nil, err
if websocketConfig != nil { }
config.Websocket = websocketConfig if websocketConfig != nil {
config.Websocket = websocketConfig
}
} }
} }
} }
// 重写规则 // 重写规则
// TODO 检查forNode参数
if IsNotNull(web.RewriteRules) { if IsNotNull(web.RewriteRules) {
refs := []*serverconfigs.HTTPRewriteRef{} var refs = []*serverconfigs.HTTPRewriteRef{}
err = json.Unmarshal(web.RewriteRules, &refs) err = json.Unmarshal(web.RewriteRules, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -346,8 +375,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
} }
// 主机跳转 // 主机跳转
// TODO 检查forNode参数
if IsNotNull(web.HostRedirects) { if IsNotNull(web.HostRedirects) {
redirects := []*serverconfigs.HTTPHostRedirectConfig{} var redirects = []*serverconfigs.HTTPHostRedirectConfig{}
err = json.Unmarshal(web.HostRedirects, &redirects) err = json.Unmarshal(web.HostRedirects, &redirects)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -357,25 +387,28 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// Fastcgi // Fastcgi
if IsNotNull(web.Fastcgi) { if IsNotNull(web.Fastcgi) {
ref := &serverconfigs.HTTPFastcgiRef{} var ref = &serverconfigs.HTTPFastcgiRef{}
err = json.Unmarshal(web.Fastcgi, ref) err = json.Unmarshal(web.Fastcgi, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.FastcgiRef = ref
if len(ref.FastcgiIds) > 0 { if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
list := []*serverconfigs.HTTPFastcgiConfig{} config.FastcgiRef = ref
for _, fastcgiId := range ref.FastcgiIds {
fastcgiConfig, err := SharedHTTPFastcgiDAO.ComposeFastcgiConfig(tx, fastcgiId) if len(ref.FastcgiIds) > 0 {
if err != nil { list := []*serverconfigs.HTTPFastcgiConfig{}
return nil, err for _, fastcgiId := range ref.FastcgiIds {
} fastcgiConfig, err := SharedHTTPFastcgiDAO.ComposeFastcgiConfig(tx, fastcgiId)
if fastcgiConfig != nil { if err != nil {
list = append(list, fastcgiConfig) return nil, err
}
if fastcgiConfig != nil {
list = append(list, fastcgiConfig)
}
} }
config.FastcgiList = list
} }
config.FastcgiList = list
} }
} }
@@ -386,19 +419,21 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
var newRefs []*serverconfigs.HTTPAuthPolicyRef if this.shouldCompose(isLocationOrGroup, forNode, authConfig.IsPrior, authConfig.IsOn) {
for _, ref := range authConfig.PolicyRefs { var newRefs []*serverconfigs.HTTPAuthPolicyRef
policyConfig, err := SharedHTTPAuthPolicyDAO.ComposePolicyConfig(tx, ref.AuthPolicyId, cacheMap) for _, ref := range authConfig.PolicyRefs {
if err != nil { policyConfig, err := SharedHTTPAuthPolicyDAO.ComposePolicyConfig(tx, ref.AuthPolicyId, cacheMap)
return nil, err if err != nil {
} return nil, err
if policyConfig != nil { }
ref.AuthPolicy = policyConfig if policyConfig != nil {
newRefs = append(newRefs, ref) ref.AuthPolicy = policyConfig
authConfig.PolicyRefs = newRefs newRefs = append(newRefs, ref)
authConfig.PolicyRefs = newRefs
}
} }
config.Auth = authConfig
} }
config.Auth = authConfig
} }
// WebP // WebP
@@ -408,7 +443,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.WebP = webpConfig if this.shouldCompose(isLocationOrGroup, forNode, webpConfig.IsPrior, webpConfig.IsOn) {
config.WebP = webpConfig
}
} }
// RemoteAddr // RemoteAddr
@@ -418,7 +455,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RemoteAddr = remoteAddrConfig if this.shouldCompose(isLocationOrGroup, forNode, remoteAddrConfig.IsPrior, remoteAddrConfig.IsOn) {
config.RemoteAddr = remoteAddrConfig
}
} }
// mergeSlashes // mergeSlashes
@@ -427,25 +466,24 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 请求限制 // 请求限制
if len(web.RequestLimit) > 0 { if len(web.RequestLimit) > 0 {
var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{} var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{}
if len(web.RequestLimit) > 0 { err = json.Unmarshal(web.RequestLimit, requestLimitConfig)
err = json.Unmarshal(web.RequestLimit, requestLimitConfig) if err != nil {
if err != nil { return nil, err
return nil, err }
} if this.shouldCompose(isLocationOrGroup, forNode, requestLimitConfig.IsPrior, requestLimitConfig.IsOn) {
config.RequestLimit = requestLimitConfig config.RequestLimit = requestLimitConfig
} }
} }
// 请求脚本 // 请求脚本
// TODO 检查forNode设置
if len(web.RequestScripts) > 0 { if len(web.RequestScripts) > 0 {
var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{} var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{}
if len(web.RequestScripts) > 0 { err = json.Unmarshal(web.RequestScripts, requestScriptsConfig)
err = json.Unmarshal(web.RequestScripts, requestScriptsConfig) if err != nil {
if err != nil { return nil, err
return nil, err
}
config.RequestScripts = requestScriptsConfig
} }
config.RequestScripts = requestScriptsConfig
} }
// UAM // UAM
@@ -455,27 +493,33 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.UAM = uamConfig if this.shouldCompose(isLocationOrGroup, forNode, uamConfig.IsPrior, uamConfig.IsOn) {
config.UAM = uamConfig
}
} }
// CC // CC
if teaconst.IsPlus && IsNotNull(web.Cc) { if teaconst.IsPlus && IsNotNull(web.Cc) {
var ccConfig = &serverconfigs.HTTPCCConfig{} var ccConfig = serverconfigs.DefaultHTTPCCConfig()
err = json.Unmarshal(web.Cc, ccConfig) err = json.Unmarshal(web.Cc, ccConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.CC = ccConfig if this.shouldCompose(isLocationOrGroup, forNode, ccConfig.IsPrior, ccConfig.IsOn) {
config.CC = ccConfig
}
} }
// Referers // Referers
if IsNotNull(web.Referers) { if IsNotNull(web.Referers) {
var referersConfig = &serverconfigs.ReferersConfig{} var referersConfig = serverconfigs.NewReferersConfig()
err = json.Unmarshal(web.Referers, referersConfig) err = json.Unmarshal(web.Referers, referersConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Referers = referersConfig if this.shouldCompose(isLocationOrGroup, forNode, referersConfig.IsPrior, referersConfig.IsOn) {
config.Referers = referersConfig
}
} }
// User-Agent // User-Agent
@@ -485,7 +529,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.UserAgent = userAgentConfig if this.shouldCompose(isLocationOrGroup, forNode, userAgentConfig.IsPrior, userAgentConfig.IsOn) {
config.UserAgent = userAgentConfig
}
} }
if cacheMap != nil { if cacheMap != nil {
@@ -1110,8 +1156,6 @@ func (this *HTTPWebDAO) UpdateWebHostRedirects(tx *dbs.Tx, webId int64, hostRedi
return this.NotifyUpdate(tx, webId) return this.NotifyUpdate(tx, webId)
} }
// 通用设置
// FindWebHostRedirects 查找主机跳转 // FindWebHostRedirects 查找主机跳转
func (this *HTTPWebDAO) FindWebHostRedirects(tx *dbs.Tx, webId int64) ([]byte, error) { func (this *HTTPWebDAO) FindWebHostRedirects(tx *dbs.Tx, webId int64) ([]byte, error) {
col, err := this.Query(tx). col, err := this.Query(tx).
@@ -1352,3 +1396,11 @@ func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
return nil return nil
} }
// 检查是否应该组合配置
func (this *HTTPWebDAO) shouldCompose(isLocationOrGroup bool, forNode bool, isPrior bool, isOn bool) bool {
if !forNode {
return true
}
return (!isLocationOrGroup && isOn) || (isLocationOrGroup && isPrior)
}

View File

@@ -159,6 +159,31 @@ func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, han
return this.NotifyUpdate(tx, websocketId) return this.NotifyUpdate(tx, websocketId)
} }
// CloneWebsocket 复制配置
func (this *HTTPWebsocketDAO) CloneWebsocket(tx *dbs.Tx, fromWebsocketId int64) (newWebsocketId int64, err error) {
websocketOne, err := this.Query(tx).
Pk(fromWebsocketId).
Find()
if err != nil || websocketOne == nil {
return 0, err
}
var websocket = websocketOne.(*HTTPWebsocket)
var op = NewHTTPWebsocketOperator()
op.State = websocket.State
op.IsOn = websocket.IsOn
if len(websocket.HandshakeTimeout) > 0 {
op.HandshakeTimeout = websocket.HandshakeTimeout
}
op.AllowAllOrigins = websocket.AllowAllOrigins
if len(websocket.AllowedOrigins) > 0 {
op.AllowedOrigins = websocket.AllowedOrigins
}
op.RequestSameOrigin = websocket.RequestSameOrigin
op.RequestOrigin = websocket.RequestOrigin
return this.SaveInt64(tx, op)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error { func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId)

View File

@@ -2,7 +2,7 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
// Websocket设置 // HTTPWebsocket Websocket设置
type HTTPWebsocket struct { type HTTPWebsocket struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
@@ -15,20 +15,22 @@ type HTTPWebsocket struct {
AllowedOrigins dbs.JSON `field:"allowedOrigins"` // 支持的源域名列表 AllowedOrigins dbs.JSON `field:"allowedOrigins"` // 支持的源域名列表
RequestSameOrigin uint8 `field:"requestSameOrigin"` // 是否请求一样的Origin RequestSameOrigin uint8 `field:"requestSameOrigin"` // 是否请求一样的Origin
RequestOrigin string `field:"requestOrigin"` // 请求Origin RequestOrigin string `field:"requestOrigin"` // 请求Origin
WebId uint64 `field:"webId"` // Web
} }
type HTTPWebsocketOperator struct { type HTTPWebsocketOperator struct {
Id interface{} // ID Id any // ID
AdminId interface{} // 管理员ID AdminId any // 管理员ID
UserId interface{} // 用户ID UserId any // 用户ID
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
State interface{} // 状态 State any // 状态
IsOn interface{} // 是否启用 IsOn any // 是否启用
HandshakeTimeout interface{} // 握手超时时间 HandshakeTimeout any // 握手超时时间
AllowAllOrigins interface{} // 是否支持所有源 AllowAllOrigins any // 是否支持所有源
AllowedOrigins interface{} // 支持的源域名列表 AllowedOrigins any // 支持的源域名列表
RequestSameOrigin interface{} // 是否请求一样的Origin RequestSameOrigin any // 是否请求一样的Origin
RequestOrigin interface{} // 请求Origin RequestOrigin any // 请求Origin
WebId any // Web
} }
func NewHTTPWebsocketOperator() *HTTPWebsocketOperator { func NewHTTPWebsocketOperator() *HTTPWebsocketOperator {

View File

@@ -75,13 +75,21 @@ func (this *IPItemDAO) EnableIPItem(tx *dbs.Tx, id int64) error {
} }
// DisableIPItem 禁用条目 // DisableIPItem 禁用条目
func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error { func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64, sourceUserId int64) error {
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil { if err != nil {
return err return err
} }
_, err = this.Query(tx). var query = this.Query(tx)
// 检查权限
if sourceUserId > 0 {
query.Where("(sourceUserId=:sourceUserId OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
}
_, err = query.
Pk(id). Pk(id).
Set("state", IPItemStateDisabled). Set("state", IPItemStateDisabled).
Set("version", version). Set("version", version).
@@ -94,7 +102,7 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
} }
// DisableIPItemsWithIP 禁用某个IP相关条目 // DisableIPItemsWithIP 禁用某个IP相关条目
func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, userId int64, listId int64) error { func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, sourceUserId int64, listId int64) error {
if len(ipFrom) == 0 { if len(ipFrom) == 0 {
return errors.New("invalid 'ipFrom'") return errors.New("invalid 'ipFrom'")
} }
@@ -106,16 +114,13 @@ func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo stri
State(IPItemStateEnabled) State(IPItemStateEnabled)
if listId > 0 { if listId > 0 {
if userId > 0 {
err := SharedIPListDAO.CheckUserIPList(tx, userId, listId)
if err != nil {
return err
}
}
query.Attr("listId", listId) query.Attr("listId", listId)
} }
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
}
ones, err := query.FindAll() ones, err := query.FindAll()
if err != nil { if err != nil {
return err return err
@@ -125,14 +130,6 @@ func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo stri
for _, one := range ones { for _, one := range ones {
var item = one.(*IPItem) var item = one.(*IPItem)
var itemId = int64(item.Id) var itemId = int64(item.Id)
var itemListId = int64(item.ListId)
if itemListId != listId && userId > 0 {
err = SharedIPListDAO.CheckUserIPList(tx, userId, itemListId)
if err != nil {
// ignore error
continue
}
}
itemIds = append(itemIds, itemId) itemIds = append(itemIds, itemId)
} }
@@ -213,11 +210,12 @@ func (this *IPItemDAO) DeleteOldItem(tx *dbs.Tx, listId int64, ipFrom string, ip
Attr("listId", listId). Attr("listId", listId).
Attr("ipFrom", ipFrom). Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo). Attr("ipTo", ipTo).
Set("state", IPItemStateEnabled). Attr("state", IPItemStateEnabled).
FindAll() FindAll()
if err != nil { if err != nil {
return err return err
} }
for _, one := range ones { for _, one := range ones {
var itemId = int64(one.(*IPItem).Id) var itemId = int64(one.(*IPItem).Id)
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
@@ -253,7 +251,8 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
sourceServerId int64, sourceServerId int64,
sourceHTTPFirewallPolicyId int64, sourceHTTPFirewallPolicyId int64,
sourceHTTPFirewallRuleGroupId int64, sourceHTTPFirewallRuleGroupId int64,
sourceHTTPFirewallRuleSetId int64) (int64, error) { sourceHTTPFirewallRuleSetId int64,
shouldNotify bool) (int64, error) {
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -282,6 +281,15 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
op.SourceHTTPFirewallRuleGroupId = sourceHTTPFirewallRuleGroupId op.SourceHTTPFirewallRuleGroupId = sourceHTTPFirewallRuleGroupId
op.SourceHTTPFirewallRuleSetId = sourceHTTPFirewallRuleSetId op.SourceHTTPFirewallRuleSetId = sourceHTTPFirewallRuleSetId
// 服务所属用户
if sourceServerId > 0 {
userId, err := SharedServerDAO.FindServerUserId(tx, sourceServerId)
if err != nil {
return 0, err
}
op.SourceUserId = userId
}
var autoAdded = listId == firewallconfigs.GlobalListId || sourceNodeId > 0 || sourceServerId > 0 || sourceHTTPFirewallPolicyId > 0 var autoAdded = listId == firewallconfigs.GlobalListId || sourceNodeId > 0 || sourceServerId > 0 || sourceHTTPFirewallPolicyId > 0
if autoAdded { if autoAdded {
op.IsRead = 0 op.IsRead = 0
@@ -301,9 +309,11 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
return itemId, nil return itemId, nil
} }
err = this.NotifyUpdate(tx, itemId) if shouldNotify {
if err != nil { err = this.NotifyUpdate(tx, itemId)
return 0, err if err != nil {
return 0, err
}
} }
return itemId, nil return itemId, nil
} }
@@ -353,10 +363,15 @@ func (this *IPItemDAO) UpdateIPItem(tx *dbs.Tx, itemId int64, ipFrom string, ipT
} }
// CountIPItemsWithListId 计算IP数量 // CountIPItemsWithListId 计算IP数量
func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, keyword string, ipFrom string, ipTo string, eventLevel string) (int64, error) { func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUserId int64, keyword string, ipFrom string, ipTo string, eventLevel string) (int64, error) {
var query = this.Query(tx). var query = this.Query(tx).
State(IPItemStateEnabled). State(IPItemStateEnabled).
Attr("listId", listId) Attr("listId", listId)
if sourceUserId > 0 {
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)"). query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
@@ -374,10 +389,15 @@ func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, keyword
} }
// ListIPItemsWithListId 查找IP列表 // ListIPItemsWithListId 查找IP列表
func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, keyword string, ipFrom string, ipTo string, eventLevel string, offset int64, size int64) (result []*IPItem, err error) { func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUserId int64, keyword string, ipFrom string, ipTo string, eventLevel string, offset int64, size int64) (result []*IPItem, err error) {
var query = this.Query(tx). var query = this.Query(tx).
State(IPItemStateEnabled). State(IPItemStateEnabled).
Attr("listId", listId) Attr("listId", listId)
if sourceUserId > 0 {
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)"). query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
@@ -403,10 +423,10 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, keyword s
// ListIPItemsAfterVersion 根据版本号查找IP列表 // ListIPItemsAfterVersion 根据版本号查找IP列表
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) { func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
UseIndex("version").
// 这里不要设置状态参数,因为我们要知道哪些是删除的 // 这里不要设置状态参数,因为我们要知道哪些是删除的
Gt("version", version). Gt("version", version).
Asc("version"). Asc("version").
Asc("id").
Limit(size). Limit(size).
Slice(&result). Slice(&result).
FindAll() FindAll()
@@ -466,8 +486,17 @@ func (this *IPItemDAO) ExistsEnabledItem(tx *dbs.Tx, itemId int64) (bool, error)
} }
// CountAllEnabledIPItems 计算数量 // CountAllEnabledIPItems 计算数量
func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string) (int64, error) { func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string) (int64, error) {
var query = this.Query(tx) 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 len(keyword) > 0 {
query.Like("ipFrom", dbutils.QuoteLike(keyword)) query.Like("ipFrom", dbutils.QuoteLike(keyword))
} }
@@ -499,8 +528,17 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, keyword string, ip str
} }
// ListAllEnabledIPItems 搜索所有IP // ListAllEnabledIPItems 搜索所有IP
func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string, offset int64, size int64) (result []*IPItem, err error) { func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string, offset int64, size int64) (result []*IPItem, err error) {
var query = this.Query(tx) 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 len(keyword) > 0 {
query.Like("ipFrom", dbutils.QuoteLike(keyword)) query.Like("ipFrom", dbutils.QuoteLike(keyword))
} }
@@ -536,11 +574,17 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, keyword string, ip stri
} }
// UpdateItemsRead 设置所有未已读 // UpdateItemsRead 设置所有未已读
func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error { func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx, sourceUserId int64) error {
return this.Query(tx). var query = this.Query(tx).
Attr("isRead", 0). Attr("isRead", 0).
Set("isRead", 1). Set("isRead", 1)
UpdateQuickly()
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
}
return query.UpdateQuickly()
} }
// CleanExpiredIPItems 清除过期数据 // CleanExpiredIPItems 清除过期数据

View File

@@ -51,12 +51,12 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
var dao = models.NewIPItemDAO() var dao = models.NewIPItemDAO()
var n = 10 var n = 10
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0) itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_ = itemId _ = itemId
/**err = dao.Query(tx).Pk(itemId).Set("state", 0).UpdateQuickly() /**err = dao.Query(tx).Pk(itemId).Attr("state", 0).UpdateQuickly()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
}**/ }**/

View File

@@ -23,32 +23,34 @@ type IPItem struct {
SourceHTTPFirewallPolicyId uint32 `field:"sourceHTTPFirewallPolicyId"` // 来源策略ID SourceHTTPFirewallPolicyId uint32 `field:"sourceHTTPFirewallPolicyId"` // 来源策略ID
SourceHTTPFirewallRuleGroupId uint32 `field:"sourceHTTPFirewallRuleGroupId"` // 来源规则集分组ID SourceHTTPFirewallRuleGroupId uint32 `field:"sourceHTTPFirewallRuleGroupId"` // 来源规则集分组ID
SourceHTTPFirewallRuleSetId uint32 `field:"sourceHTTPFirewallRuleSetId"` // 来源规则集ID SourceHTTPFirewallRuleSetId uint32 `field:"sourceHTTPFirewallRuleSetId"` // 来源规则集ID
SourceUserId uint64 `field:"sourceUserId"` // 用户ID
IsRead bool `field:"isRead"` // 是否已读 IsRead bool `field:"isRead"` // 是否已读
} }
type IPItemOperator struct { type IPItemOperator struct {
Id interface{} // ID Id any // ID
ListId interface{} // 所属名单ID ListId any // 所属名单ID
Type interface{} // 类型 Type any // 类型
IpFrom interface{} // 开始IP IpFrom any // 开始IP
IpTo interface{} // 结束IP IpTo any // 结束IP
IpFromLong interface{} // 开始IP整型 IpFromLong any // 开始IP整型
IpToLong interface{} // 结束IP整型 IpToLong any // 结束IP整型
Version interface{} // 版本 Version any // 版本
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
UpdatedAt interface{} // 修改时间 UpdatedAt any // 修改时间
Reason interface{} // 加入说明 Reason any // 加入说明
EventLevel interface{} // 事件级别 EventLevel any // 事件级别
State interface{} // 状态 State any // 状态
ExpiredAt interface{} // 过期时间 ExpiredAt any // 过期时间
ServerId interface{} // 有效范围服务ID ServerId any // 有效范围服务ID
NodeId interface{} // 有效范围节点ID NodeId any // 有效范围节点ID
SourceNodeId interface{} // 来源节点ID SourceNodeId any // 来源节点ID
SourceServerId interface{} // 来源服务ID SourceServerId any // 来源服务ID
SourceHTTPFirewallPolicyId interface{} // 来源策略ID SourceHTTPFirewallPolicyId any // 来源策略ID
SourceHTTPFirewallRuleGroupId interface{} // 来源规则集分组ID SourceHTTPFirewallRuleGroupId any // 来源规则集分组ID
SourceHTTPFirewallRuleSetId interface{} // 来源规则集ID SourceHTTPFirewallRuleSetId any // 来源规则集ID
IsRead interface{} // 是否已读 SourceUserId any // 用户ID
IsRead any // 是否已读
} }
func NewIPItemOperator() *IPItemOperator { func NewIPItemOperator() *IPItemOperator {

View File

@@ -72,7 +72,7 @@ func (this *IPLibraryFileDAO) FindEnabledIPLibraryFile(tx *dbs.Tx, id int64) (*I
} }
// CreateLibraryFile 创建文件 // CreateLibraryFile 创建文件
func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, template string, emptyValues []string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) { func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, template string, emptyValues []string, password string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) {
var op = NewIPLibraryFileOperator() var op = NewIPLibraryFileOperator()
op.Name = name op.Name = name
op.Template = template op.Template = template
@@ -86,6 +86,8 @@ func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, templat
} }
op.EmptyValues = emptyValuesJSON op.EmptyValues = emptyValuesJSON
op.Password = password
op.FileId = fileId op.FileId = fileId
if countries == nil { if countries == nil {
@@ -337,7 +339,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countries = []*iplibrary.Country{} var countries = []*iplibrary.Country{}
for _, country := range dbCountries { for _, country := range dbCountries {
countries = append(countries, &iplibrary.Country{ countries = append(countries, &iplibrary.Country{
Id: country.Id, Id: types.Uint16(country.Id),
Name: country.DisplayName(), Name: country.DisplayName(),
Codes: country.AllCodes(), Codes: country.AllCodes(),
}) })
@@ -352,7 +354,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var provinces = []*iplibrary.Province{} var provinces = []*iplibrary.Province{}
for _, province := range dbProvinces { for _, province := range dbProvinces {
provinces = append(provinces, &iplibrary.Province{ provinces = append(provinces, &iplibrary.Province{
Id: province.Id, Id: types.Uint16(province.Id),
Name: province.DisplayName(), Name: province.DisplayName(),
Codes: province.AllCodes(), Codes: province.AllCodes(),
}) })
@@ -397,7 +399,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var providers = []*iplibrary.Provider{} var providers = []*iplibrary.Provider{}
for _, provider := range dbProviders { for _, provider := range dbProviders {
providers = append(providers, &iplibrary.Provider{ providers = append(providers, &iplibrary.Provider{
Id: provider.Id, Id: types.Uint16(provider.Id),
Name: provider.DisplayName(), Name: provider.DisplayName(),
Codes: provider.AllCodes(), Codes: provider.AllCodes(),
}) })
@@ -414,7 +416,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
Towns: towns, Towns: towns,
Providers: providers, Providers: providers,
} }
writer, err := iplibrary.NewFileWriter(filePath, meta) writer, err := iplibrary.NewFileWriter(filePath, meta, libraryFile.Password)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -18,6 +18,7 @@ type IPLibraryFile struct {
Towns dbs.JSON `field:"towns"` // 区县 Towns dbs.JSON `field:"towns"` // 区县
Providers dbs.JSON `field:"providers"` // ISP服务商 Providers dbs.JSON `field:"providers"` // ISP服务商
Code string `field:"code"` // 文件代号 Code string `field:"code"` // 文件代号
Password string `field:"password"` // 密码
CreatedAt uint64 `field:"createdAt"` // 上传时间 CreatedAt uint64 `field:"createdAt"` // 上传时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
@@ -37,6 +38,7 @@ type IPLibraryFileOperator struct {
Towns any // 区县 Towns any // 区县
Providers any // ISP服务商 Providers any // ISP服务商
Code any // 文件代号 Code any // 文件代号
Password any // 密码
CreatedAt any // 上传时间 CreatedAt any // 上传时间
State any // 状态 State any // 状态
} }

View File

@@ -60,11 +60,11 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
} }
// CountLogs 计算所有日志数量 // CountLogs 计算所有日志数量
func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword string, userType string) (int64, error) { func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword string, userType string, level string) (int64, error) {
dayFrom = this.formatDay(dayFrom) dayFrom = this.formatDay(dayFrom)
dayTo = this.formatDay(dayTo) dayTo = this.formatDay(dayTo)
query := this.Query(tx) var query = this.Query(tx)
if len(dayFrom) > 0 { if len(dayFrom) > 0 {
query.Gte("day", dayFrom) query.Gte("day", dayFrom)
@@ -76,6 +76,9 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
query.Where("(description LIKE :keyword OR ip LIKE :keyword OR action LIKE :keyword)"). query.Where("(description LIKE :keyword OR ip LIKE :keyword OR action LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型 // 用户类型
switch userType { switch userType {
@@ -89,11 +92,11 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
} }
// ListLogs 列出单页日志 // ListLogs 列出单页日志
func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom string, dayTo string, keyword string, userType string) (result []*Log, err error) { func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom string, dayTo string, keyword string, userType string, level string) (result []*Log, err error) {
dayFrom = this.formatDay(dayFrom) dayFrom = this.formatDay(dayFrom)
dayTo = this.formatDay(dayTo) dayTo = this.formatDay(dayTo)
query := this.Query(tx) var query = this.Query(tx)
if len(dayFrom) > 0 { if len(dayFrom) > 0 {
query.Gte("day", dayFrom) query.Gte("day", dayFrom)
} }
@@ -105,6 +108,10 @@ func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom strin
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型 // 用户类型
switch userType { switch userType {
case "admin": case "admin":

View File

@@ -52,7 +52,9 @@ const (
MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃 MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃 MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃
MessageTypeConnectivity MessageType = "Connectivity" MessageTypeConnectivity MessageType = "Connectivity" // 连通性
MessageTypeNodeSchedule MessageType = "NodeSchedule" // 节点调度信息
MessageTypeNodeOfflineDay MessageType = "NodeOfflineDay" // 节点到下线日期
) )
type MessageDAO dbs.DAO type MessageDAO dbs.DAO
@@ -155,7 +157,7 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, role string, clusterId int
// CreateMessage 创建普通消息 // CreateMessage 创建普通消息
func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error { func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
body = utils.LimitString(subject, 100) subject = utils.LimitString(subject, 100)
body = utils.LimitString(body, 1024) body = utils.LimitString(body, 1024)
var op = NewMessageOperator() var op = NewMessageOperator()

View File

@@ -0,0 +1,33 @@
package nameservers
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NSDomainStateEnabled = 1 // 已启用
NSDomainStateDisabled = 0 // 已禁用
)
type NSDomainDAO dbs.DAO
func NewNSDomainDAO() *NSDomainDAO {
return dbs.NewDAO(&NSDomainDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNSDomains",
Model: new(NSDomain),
PkName: "id",
},
}).(*NSDomainDAO)
}
var SharedNSDomainDAO *NSDomainDAO
func init() {
dbs.OnReady(func() {
SharedNSDomainDAO = NewNSDomainDAO()
})
}

View File

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

View File

@@ -4,35 +4,37 @@ import "github.com/iwind/TeaGo/dbs"
// NSDomain DNS域名 // NSDomain DNS域名
type NSDomain struct { type NSDomain struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名 Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置 Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间 VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
CreatedAt uint64 `field:"createdAt"` // 创建时间 RecordsHealthCheck dbs.JSON `field:"recordsHealthCheck"` // 记录健康检查设置
Version uint64 `field:"version"` // 版本号 CreatedAt uint64 `field:"createdAt"` // 创建时间
Status string `field:"status"` // 状态none|verified Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态 Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
} }
type NSDomainOperator struct { type NSDomainOperator struct {
Id any // ID Id any // ID
ClusterId any // 集群ID ClusterId any // 集群ID
UserId any // 用户ID UserId any // 用户ID
IsOn any // 是否启用 IsOn any // 是否启用
Name any // 域名 Name any // 域名
GroupIds any // 分组ID GroupIds any // 分组ID
Tsig any // TSIG配置 Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间 VerifyExpiresAt any // 验证TXT过期时间
CreatedAt any // 创建时间 RecordsHealthCheck any // 记录健康检查设置
Version any // 版本号 CreatedAt any // 创建时间
Status any // 状态none|verified Version any // 版本号
State any // 状态 Status any // 状态none|verified
State any // 状态
} }
func NewNSDomainOperator() *NSDomainOperator { func NewNSDomainOperator() *NSDomainOperator {

View File

@@ -20,6 +20,10 @@ type NSRecord struct {
Ttl uint32 `field:"ttl"` // TTL Ttl uint32 `field:"ttl"` // TTL
Weight uint32 `field:"weight"` // 权重 Weight uint32 `field:"weight"` // 权重
RouteIds dbs.JSON `field:"routeIds"` // 线路 RouteIds dbs.JSON `field:"routeIds"` // 线路
HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查配置
CountUp uint32 `field:"countUp"` // 连续上线次数
CountDown uint32 `field:"countDown"` // 连续离线次数
IsUp bool `field:"isUp"` // 是否在线
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号 Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
@@ -42,6 +46,10 @@ type NSRecordOperator struct {
Ttl any // TTL Ttl any // TTL
Weight any // 权重 Weight any // 权重
RouteIds any // 线路 RouteIds any // 线路
HealthCheck any // 健康检查配置
CountUp any // 连续上线次数
CountDown any // 连续离线次数
IsUp any // 是否在线
CreatedAt any // 创建时间 CreatedAt any // 创建时间
Version any // 版本号 Version any // 版本号
State any // 状态 State any // 状态

View File

@@ -0,0 +1,63 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeActionStateEnabled = 1 // 已启用
NodeActionStateDisabled = 0 // 已禁用
)
type NodeActionDAO dbs.DAO
func NewNodeActionDAO() *NodeActionDAO {
return dbs.NewDAO(&NodeActionDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeActions",
Model: new(NodeAction),
PkName: "id",
},
}).(*NodeActionDAO)
}
var SharedNodeActionDAO *NodeActionDAO
func init() {
dbs.OnReady(func() {
SharedNodeActionDAO = NewNodeActionDAO()
})
}
// EnableNodeAction 启用条目
func (this *NodeActionDAO) EnableNodeAction(tx *dbs.Tx, id uint64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NodeActionStateEnabled).
Update()
return err
}
// DisableNodeAction 禁用条目
func (this *NodeActionDAO) DisableNodeAction(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NodeActionStateDisabled).
Update()
return err
}
// FindEnabledNodeAction 查找启用中的条目
func (this *NodeActionDAO) FindEnabledNodeAction(tx *dbs.Tx, id int64) (*NodeAction, error) {
result, err := this.Query(tx).
Pk(id).
State(NodeActionStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeAction), err
}

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,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
// NodeAction 节点智能调度设置
type NodeAction struct {
Id uint64 `field:"id"` // ID
NodeId uint64 `field:"nodeId"` // 节点ID
Role string `field:"role"` // 角色
IsOn bool `field:"isOn"` // 是否启用
Conds dbs.JSON `field:"conds"` // 条件
Action dbs.JSON `field:"action"` // 动作
Duration dbs.JSON `field:"duration"` // 持续时间
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
}
type NodeActionOperator struct {
Id any // ID
NodeId any // 节点ID
Role any // 角色
IsOn any // 是否启用
Conds any // 条件
Action any // 动作
Duration any // 持续时间
Order any // 排序
State any // 状态
}
func NewNodeActionOperator() *NodeActionOperator {
return &NodeActionOperator{}
}

View File

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

View File

@@ -996,7 +996,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx). cluster, err := this.Query(tx).
Pk(clusterId). Pk(clusterId).
State(NodeClusterStateEnabled). State(NodeClusterStateEnabled).
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables"). Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables").
Find() Find()
if err != nil || cluster == nil { if err != nil || cluster == nil {
return nil, err return nil, err
@@ -1077,7 +1077,7 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return err return err
} }
return this.NotifyUpdate(tx, clusterId) return this.NotifyUAMUpdate(tx, clusterId)
} }
uamPolicyJSON, err := json.Marshal(uamPolicy) uamPolicyJSON, err := json.Marshal(uamPolicy)
@@ -1092,10 +1092,10 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return err return err
} }
return this.NotifyUpdate(tx, clusterId) return this.NotifyUAMUpdate(tx, clusterId)
} }
// FindClusterUAMPolicy 查询设置 // FindClusterUAMPolicy 查询UAM设置
func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) { func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) {
var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId) var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId)
if cacheMap != nil { if cacheMap != nil {
@@ -1125,6 +1125,146 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return policy, nil return policy, nil
} }
// UpdateClusterHTTPCCPolicy 修改CC策略设置
func (this *NodeClusterDAO) UpdateClusterHTTPCCPolicy(tx *dbs.Tx, clusterId int64, httpCCPolicy *nodeconfigs.HTTPCCPolicy) error {
if httpCCPolicy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("cc", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPCCUpdate(tx, clusterId)
}
httpCCPolicyJSON, err := json.Marshal(httpCCPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("cc", httpCCPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPCCUpdate(tx, clusterId)
}
// FindClusterHTTPCCPolicy 查询CC策略设置
func (this *NodeClusterDAO) FindClusterHTTPCCPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTPCCPolicy, error) {
var cacheKey = this.Table + ":FindClusterHTTPCCPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTPCCPolicy), nil
}
}
httpCCJSON, err := this.Query(tx).
Pk(clusterId).
Result("cc").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(httpCCJSON) {
return nodeconfigs.NewHTTPCCPolicy(), nil
}
var policy = nodeconfigs.NewHTTPCCPolicy()
err = json.Unmarshal(httpCCJSON, policy)
if err != nil {
return nil, err
}
return policy, nil
}
// UpdateClusterHTTPPagesPolicy 修改自定义页面设置
func (this *NodeClusterDAO) UpdateClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, httpPagesPolicy *nodeconfigs.HTTPPagesPolicy) error {
if httpPagesPolicy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("httpPages", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPPagesPolicyUpdate(tx, clusterId)
}
// 移除不需要保存的内容
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range httpPagesPolicy.Pages {
newPages = append(newPages, &serverconfigs.HTTPPageConfig{Id: page.Id})
}
httpPagesPolicy.Pages = newPages
httpPagesPolicyJSON, err := json.Marshal(httpPagesPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("httpPages", httpPagesPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPPagesPolicyUpdate(tx, clusterId)
}
// FindClusterHTTPPagesPolicy 查询自定义页面设置
func (this *NodeClusterDAO) FindClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTPPagesPolicy, error) {
var cacheKey = this.Table + ":FindClusterHTTPPagesPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTPPagesPolicy), nil
}
}
pagesJSON, err := this.Query(tx).
Pk(clusterId).
Result("httpPages").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(pagesJSON) {
return nodeconfigs.NewHTTPPagesPolicy(), nil
}
var policy = nodeconfigs.NewHTTPPagesPolicy()
err = json.Unmarshal(pagesJSON, policy)
if err != nil {
return nil, err
}
// 读取Page信息
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range policy.Pages {
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id, cacheMap)
if err != nil {
return nil, err
}
if pageConfig == nil {
continue
}
newPages = append(newPages, pageConfig)
}
policy.Pages = newPages
return policy, nil
}
// FindClusterDDoSProtection 获取集群的DDoS设置 // FindClusterDDoSProtection 获取集群的DDoS设置
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) { func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx). one, err := this.Query(tx).
@@ -1212,6 +1352,21 @@ func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeConfigChanged) return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeConfigChanged)
} }
// NotifyUAMUpdate 通知UAM更新
func (this *NodeClusterDAO) NotifyUAMUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeUAMPolicyChanged)
}
// NotifyHTTPCCUpdate 通知HTTP CC更新
func (this *NodeClusterDAO) NotifyHTTPCCUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPCCPolicyChanged)
}
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
}
// NotifyDNSUpdate 通知DNS更新 // NotifyDNSUpdate 通知DNS更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录 // TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error { func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {

View File

@@ -41,6 +41,8 @@ type NodeCluster struct {
AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动 AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动
AutoInstallNftables bool `field:"autoInstallNftables"` // 自动安装nftables AutoInstallNftables bool `field:"autoInstallNftables"` // 自动安装nftables
IsAD bool `field:"isAD"` // 是否为高防集群 IsAD bool `field:"isAD"` // 是否为高防集群
HttpPages dbs.JSON `field:"httpPages"` // 自定义页面设置
Cc dbs.JSON `field:"cc"` // CC设置
} }
type NodeClusterOperator struct { type NodeClusterOperator struct {
@@ -81,6 +83,8 @@ type NodeClusterOperator struct {
AutoRemoteStart any // 自动远程启动 AutoRemoteStart any // 自动远程启动
AutoInstallNftables any // 自动安装nftables AutoInstallNftables any // 自动安装nftables
IsAD any // 是否为高防集群 IsAD any // 是否为高防集群
HttpPages any // 自定义页面设置
Cc any // CC设置
} }
func NewNodeClusterOperator() *NodeClusterOperator { func NewNodeClusterOperator() *NodeClusterOperator {

View File

@@ -356,7 +356,7 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
// 关键词 // 关键词
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))"). query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR "+this.Table+".id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
@@ -435,6 +435,16 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
valueField = "load1m" valueField = "load1m"
isAsc = false isAsc = false
ifNullValue = -1 ifNullValue = -1
case "connectionsAsc":
valueItem = "connections"
valueField = "total"
isAsc = true
ifNullValue = 1000
case "connectionsDesc":
valueItem = "connections"
valueField = "total"
isAsc = false
ifNullValue = -1
default: default:
query.Desc("level") query.Desc("level")
} }
@@ -830,7 +840,24 @@ func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *node
Set("isActive", true). Set("isActive", true).
Set("status", nodeStatusJSON). Set("status", nodeStatusJSON).
Update() Update()
return err if err != nil {
return err
}
// 自动设置安装状态
isInstalled, err := this.Query(tx).
Pk(nodeId).
Result("isInstalled").
FindBoolCol()
if err != nil {
return err
}
if !isInstalled {
return this.UpdateNodeIsInstalled(tx, nodeId, true)
}
return nil
} }
// FindNodeStatus 获取节点状态 // FindNodeStatus 获取节点状态
@@ -875,7 +902,10 @@ func (this *NodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstalled
Set("isInstalled", isInstalled). Set("isInstalled", isInstalled).
Set("installStatus", "null"). // 重置安装状态 Set("installStatus", "null"). // 重置安装状态
Update() Update()
return err if err != nil {
return err
}
return this.NotifyDNSUpdate(tx, nodeId)
} }
// FindNodeInstallStatus 查询节点的安装状态 // FindNodeInstallStatus 查询节点的安装状态
@@ -932,11 +962,16 @@ func (this *NodeDAO) UpdateNodeInstallStatus(tx *dbs.Tx, nodeId int64, status *N
// ComposeNodeConfig 组合配置 // ComposeNodeConfig 组合配置
// TODO 提升运行速度 // TODO 提升运行速度
func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils.CacheMap) (*nodeconfigs.NodeConfig, error) { func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*nodeconfigs.NodeConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
// 放入到缓存中,以便于后面继续使用
if dataMap != nil {
cacheMap.Put("DataMap", dataMap)
}
node, err := this.FindEnabledNode(tx, nodeId) node, err := this.FindEnabledNode(tx, nodeId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -951,6 +986,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
var config = &nodeconfigs.NodeConfig{ var config = &nodeconfigs.NodeConfig{
Id: int64(node.Id), Id: int64(node.Id),
Edition: teaconst.Edition,
NodeId: node.UniqueId, NodeId: node.UniqueId,
Secret: node.Secret, Secret: node.Secret,
IsOn: node.IsOn, IsOn: node.IsOn,
@@ -963,8 +999,17 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
GroupId: int64(node.GroupId), GroupId: int64(node.GroupId),
EnableIPLists: node.EnableIPLists, EnableIPLists: node.EnableIPLists,
APINodeAddrs: node.DecodeAPINodeAddrs(), APINodeAddrs: node.DecodeAPINodeAddrs(),
DataMap: dataMap,
} }
// 待更新服务ID
updatingServerListId, err := SharedUpdatingServerListDAO.FindLatestId(tx)
if err != nil {
return nil, err
}
config.UpdatingServerListId = updatingServerListId
// API节点IP // API节点IP
apiNodeIPs, err := SharedAPINodeDAO.FindAllEnabledAPIAccessIPs(tx, cacheMap) apiNodeIPs, err := SharedAPINodeDAO.FindAllEnabledAPIAccessIPs(tx, cacheMap)
if err != nil { if err != nil {
@@ -999,7 +1044,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
} }
for _, server := range servers { for _, server := range servers {
serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, false, cacheMap, true, false) serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, false, dataMap, cacheMap, true, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1040,6 +1085,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
var clusterIndex = 0 var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{} config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{} config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
config.HTTPCCPolicies = map[int64]*nodeconfigs.HTTPCCPolicy{}
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
var allowIPMaps = map[string]bool{} var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds { for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap) nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
@@ -1133,6 +1180,49 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
config.UAMPolicies[clusterId] = uamPolicy config.UAMPolicies[clusterId] = uamPolicy
} }
// HTTP CC Policy
if IsNotNull(nodeCluster.Cc) {
var ccPolicy = nodeconfigs.NewHTTPCCPolicy()
err = json.Unmarshal(nodeCluster.Cc, ccPolicy)
if err != nil {
return nil, err
}
// 集成默认设置
for i := 0; i < len(serverconfigs.DefaultHTTPCCThresholds); i ++ {
if i < len(ccPolicy.Thresholds) {
ccPolicy.Thresholds[i].MergeIfEmpty(serverconfigs.DefaultHTTPCCThresholds[i])
}
}
config.HTTPCCPolicies[clusterId] = ccPolicy
}
// HTTP Pages Policy
if IsNotNull(nodeCluster.HttpPages) {
var httpPagesPolicy = nodeconfigs.NewHTTPPagesPolicy()
err = json.Unmarshal(nodeCluster.HttpPages, httpPagesPolicy)
if err != nil {
return nil, err
}
if httpPagesPolicy.IsOn {
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range httpPagesPolicy.Pages {
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id, cacheMap)
if err != nil {
return nil, err
}
if pageConfig != nil && pageConfig.IsOn {
newPages = append(newPages, pageConfig)
}
}
httpPagesPolicy.Pages = newPages
if len(newPages) > 0 {
config.HTTPPagesPolicies[clusterId] = httpPagesPolicy
}
}
}
// 自动安装nftables // 自动安装nftables
if clusterIndex == 0 { if clusterIndex == 0 {
config.AutoInstallNftables = nodeCluster.AutoInstallNftables config.AutoInstallNftables = nodeCluster.AutoInstallNftables
@@ -1349,7 +1439,7 @@ func (this *NodeDAO) CountAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64)
func (this *NodeDAO) FindAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64) (result []*Node, err error) { func (this *NodeDAO) FindAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64) (result []*Node, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Where("id IN (SELECT nodeId FROM edgeNodeLogins WHERE type='ssh' AND JSON_CONTAINS(params, :grantParam))"). Where("id IN (SELECT nodeId FROM edgeNodeLogins WHERE type='ssh' AND JSON_CONTAINS(params, :grantParam) AND state=1)").
Param("grantParam", string(maps.Map{"grantId": grantId}.AsJSON())). Param("grantParam", string(maps.Map{"grantId": grantId}.AsJSON())).
Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)"). Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)").
Slice(&result). Slice(&result).
@@ -1485,7 +1575,7 @@ func (this *NodeDAO) UpdateNodeRegionId(tx *dbs.Tx, nodeId int64, regionId int64
} }
// FindAllEnabledNodesDNSWithClusterId 获取一个集群的节点DNS信息 // FindAllEnabledNodesDNSWithClusterId 获取一个集群的节点DNS信息
func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, includingLnNodes bool) (result []*Node, err error) { func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, includingLnNodes bool, isInstalled bool) (result []*Node, err error) {
if clusterId <= 0 { if clusterId <= 0 {
return nil, nil return nil, nil
} }
@@ -1504,7 +1594,8 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("isOn", true). Attr("isOn", true).
Attr("isUp", true). Attr("isUp", true).
Result("id", "name", "dnsRoutes", "isOn"). Attr("isInstalled", isInstalled).
Result("id", "name", "dnsRoutes", "isOn", "offlineDay", "actionStatus", "isBackupForCluster", "isBackupForGroup", "backupIPs", "clusterId", "groupId").
DescPk(). DescPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
@@ -1529,7 +1620,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error)
one, err := this.Query(tx). one, err := this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Pk(nodeId). Pk(nodeId).
Result("id", "name", "dnsRoutes", "clusterId", "isOn"). Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus").
Find() Find()
if one == nil { if one == nil {
return nil, err return nil, err

View File

@@ -18,3 +18,8 @@ func (this *NodeDAO) loadServersFromCluster(tx *dbs.Tx, clusterId int64, serverI
func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error { func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
return nil return nil
} }
// CheckNodeIPAddresses 检查节点IP地址
func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) {
return
}

View File

@@ -4,9 +4,11 @@
package models_test package models_test
import ( import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
@@ -47,21 +49,40 @@ func TestNodeDAO_FindEnabledNodeClusterIds(t *testing.T) {
func TestNodeDAO_ComposeNodeConfig(t *testing.T) { func TestNodeDAO_ComposeNodeConfig(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
before := time.Now() var before = time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
var tx *dbs.Tx var tx *dbs.Tx
var cacheMap = utils.NewCacheMap() var cacheMap = utils.NewCacheMap()
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, cacheMap) var dataMap = shared.NewDataMap()
//var dataMap *nodeconfigs.DataMap
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, dataMap, cacheMap)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
nodeConfig.DataMap = dataMap
t.Log(len(nodeConfig.Servers), "servers") t.Log(len(nodeConfig.Servers), "servers")
t.Log(cacheMap.Len(), "items") t.Log(cacheMap.Len(), "items")
// old: 77ms => new: 56ms t.Log(time.Since(before).Seconds()*1000, "ms")
data, err := json.Marshal(nodeConfig)
if err != nil {
t.Fatal(err)
}
t.Log(len(data), "bytes")
{
nodeConfig, err = models.SharedNodeDAO.ComposeNodeConfig(tx, 148, dataMap, cacheMap)
if err != nil {
t.Fatal(err)
}
t.Log(len(nodeConfig.DataMap.Map), "items in dataMap")
data, err = json.Marshal(nodeConfig)
if err != nil {
t.Fatal(err)
}
t.Log(len(data), "bytes")
}
} }
func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) { func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) {
@@ -71,7 +92,7 @@ func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
var cacheMap = utils.NewCacheMap() var cacheMap = utils.NewCacheMap()
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, cacheMap) nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, nil, cacheMap)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -307,7 +307,7 @@ func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddressId(tx *dbs.Tx, nodeId
FindInt64Col(0) FindInt64Col(0)
} }
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问的IP地址 // FindNodeAccessAndUpIPAddresses 查找节点所有的可访问且在线的IP地址
func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) { func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 { if len(role) == 0 {
role = nodeconfigs.NodeRoleNode role = nodeconfigs.NodeRoleNode
@@ -326,6 +326,24 @@ func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId
return return
} }
// FindNodeAccessIPAddresses 查找节点所有的可访问的IP地址包括在线和离线
func (this *NodeIPAddressDAO) FindNodeAccessIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 {
role = nodeconfigs.NodeRoleNode
}
_, err = this.Query(tx).
Attr("role", role).
Attr("nodeId", nodeId).
State(NodeIPAddressStateEnabled).
Attr("canAccess", true).
Attr("isOn", true).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledIPAddresses 计算IP地址数量 // CountAllEnabledIPAddresses 计算IP地址数量
// TODO 目前支持边缘节点将来支持NS节点 // TODO 目前支持边缘节点将来支持NS节点
func (this *NodeIPAddressDAO) CountAllEnabledIPAddresses(tx *dbs.Tx, role string, nodeClusterId int64, upState configutils.BoolState, keyword string) (int64, error) { func (this *NodeIPAddressDAO) CountAllEnabledIPAddresses(tx *dbs.Tx, role string, nodeClusterId int64, upState configutils.BoolState, keyword string) (int64, error) {

View File

@@ -43,6 +43,12 @@ type Node struct {
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器 DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
EnableIPLists bool `field:"enableIPLists"` // 启用IP名单 EnableIPLists bool `field:"enableIPLists"` // 启用IP名单
ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址 ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址
OfflineDay string `field:"offlineDay"` // 下线日期YYYYMMDD
OfflineIsNotified bool `field:"offlineIsNotified"` // 下线是否已通知
IsBackupForCluster bool `field:"isBackupForCluster"` // 是否为集群备用节点
IsBackupForGroup bool `field:"isBackupForGroup"` // 是否为分组备用节点
BackupIPs dbs.JSON `field:"backupIPs"` // 备用IP
ActionStatus dbs.JSON `field:"actionStatus"` // 当前动作配置
} }
type NodeOperator struct { type NodeOperator struct {
@@ -85,6 +91,12 @@ type NodeOperator struct {
DnsResolver any // DNS解析器 DnsResolver any // DNS解析器
EnableIPLists any // 启用IP名单 EnableIPLists any // 启用IP名单
ApiNodeAddrs any // API节点地址 ApiNodeAddrs any // API节点地址
OfflineDay any // 下线日期YYYYMMDD
OfflineIsNotified any // 下线是否已通知
IsBackupForCluster any // 是否为集群备用节点
IsBackupForGroup any // 是否为分组备用节点
BackupIPs any // 备用IP
ActionStatus any // 当前动作配置
} }
func NewNodeOperator() *NodeOperator { func NewNodeOperator() *NodeOperator {

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort" "sort"
"time" "time"
) )
@@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) {
if len(this.InstallStatus) == 0 { if len(this.InstallStatus) == 0 {
return NewNodeInstallStatus(), nil return NewNodeInstallStatus(), nil
} }
status := &NodeInstallStatus{} var status = &NodeInstallStatus{}
err := json.Unmarshal(this.InstallStatus, status) err := json.Unmarshal(this.InstallStatus, status)
if err != nil { if err != nil {
return NewNodeInstallStatus(), err return NewNodeInstallStatus(), err
@@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
if len(this.Status) == 0 { if len(this.Status) == 0 {
return nil, nil return nil, nil
} }
status := &nodeconfigs.NodeStatus{} var status = &nodeconfigs.NodeStatus{}
err := json.Unmarshal(this.Status, status) err := json.Unmarshal(this.Status, status)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
// DNSRouteCodes 所有的DNS线路 // DNSRouteCodes 所有的DNS线路
func (this *Node) DNSRouteCodes() map[int64][]string { func (this *Node) DNSRouteCodes() map[int64][]string {
routes := map[int64][]string{} // domainId => routes var routes = map[int64][]string{} // domainId => routes
if len(this.DnsRoutes) == 0 { if len(this.DnsRoutes) == 0 {
return routes return routes
} }
@@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string {
// DNSRouteCodesForDomainId DNS线路 // DNSRouteCodesForDomainId DNS线路
func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) { func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) {
routes := map[int64][]string{} // domainId => routes var routes = map[int64][]string{} // domainId => routes
if len(this.DnsRoutes) == 0 { if len(this.DnsRoutes) == 0 {
return nil, nil return nil, nil
} }
@@ -80,7 +81,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
// DecodeConnectedAPINodeIds 连接的API // DecodeConnectedAPINodeIds 连接的API
func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) { func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
apiNodeIds := []int64{} var apiNodeIds = []int64{}
if IsNotNull(this.ConnectedAPINodes) { if IsNotNull(this.ConnectedAPINodes) {
err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds) err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
if err != nil { if err != nil {
@@ -214,3 +215,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
} }
return result return result
} }
// CheckIsOffline 检查是否已经离线
func (this *Node) CheckIsOffline() bool {
return len(this.OfflineDay) > 0 && this.OfflineDay < timeutil.Format("Ymd")
}

View File

@@ -0,0 +1,9 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
// HasScheduleSettings 检查是否设置了调度
func (this *Node) HasScheduleSettings() bool {
return false
}

View File

@@ -24,6 +24,10 @@ const (
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化 NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化 NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化 NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
// NS相关 // NS相关
@@ -236,6 +240,7 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
var query = this.Query(tx). var query = this.Query(tx).
Attr("role", role). Attr("role", role).
Attr("nodeId", nodeId). Attr("nodeId", nodeId).
UseIndex("nodeId").
Asc("version") Asc("version")
if version > 0 { if version > 0 {
query.Lt("LENGTH(version)", 19) // 兼容以往版本 query.Lt("LENGTH(version)", 19) // 兼容以往版本
@@ -294,8 +299,8 @@ func (this *NodeTaskDAO) FindAllDoingNodeTasksWithClusterId(tx *dbs.Tx, role str
Gt("nodeId", 0). Gt("nodeId", 0).
Where("(isDone=0 OR (isDone=1 AND isOk=0))"). Where("(isDone=0 OR (isDone=1 AND isOk=0))").
Desc("isDone"). Desc("isDone").
Asc().
Asc("nodeId"). Asc("nodeId").
AscPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
return return

View File

@@ -1,17 +1,19 @@
package models package models_test
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"testing" "testing"
"time"
) )
func TestNodeTaskDAO_CreateNodeTask(t *testing.T) { func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -22,7 +24,7 @@ func TestNodeTaskDAO_CreateClusterTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -33,9 +35,22 @@ func TestNodeTaskDAO_ExtractClusterTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") t.Log("ok")
} }
func TestNodeTaskDAO_FindDoingNodeTasks(t *testing.T) {
var tx *dbs.Tx
var dao = models.NewNodeTaskDAO()
var before = time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
_, err := dao.FindDoingNodeTasks(tx, "node", 48, 0)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,4 +1,4 @@
package stats package models
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
@@ -84,7 +84,9 @@ func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int
if err != nil { if err != nil {
return err return err
} }
return nil
// 触发钩子
return this.increaseDailyStatHook(tx, role, nodeId)
} }
// FindDailyStats 获取日期之间统计 // FindDailyStats 获取日期之间统计
@@ -117,6 +119,21 @@ func (this *NodeTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, role string, nod
return result, nil return result, nil
} }
// SumDailyStat 计算日期之间的总和
func (this *NodeTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, role string, nodeId int64, dayFrom string, dayTo string) (*NodeTrafficDailyStat, error) {
one, err := this.Query(tx).
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes").
Attr("nodeId", nodeId).
Attr("role", role).
Between("day", dayFrom, dayTo).
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*NodeTrafficDailyStat), nil
}
// Clean 清理历史数据 // Clean 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))

View File

@@ -0,0 +1,14 @@
// Copyright 2023 Liuxiangchao iwind.liu@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"
)
// 增加日统计Hook
func (this *NodeTrafficDailyStatDAO) increaseDailyStatHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64) error {
return nil
}

View File

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

View File

@@ -1,4 +1,4 @@
package stats package models
// NodeTrafficDailyStat 总的流量统计(按天) // NodeTrafficDailyStat 总的流量统计(按天)
type NodeTrafficDailyStat struct { type NodeTrafficDailyStat struct {

View File

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

View File

@@ -37,11 +37,15 @@ func init() {
// CreateValue 创建值 // CreateValue 创建值
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error { func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
if len(valueJSON) == 0 {
return errors.New("'valueJSON' should not be nil")
}
var day = timeutil.FormatTime("Ymd", createdAt) var day = timeutil.FormatTime("Ymd", createdAt)
var hour = timeutil.FormatTime("YmdH", createdAt) var hour = timeutil.FormatTime("YmdH", createdAt)
var minute = timeutil.FormatTime("YmdHi", createdAt) var minute = timeutil.FormatTime("YmdHi", createdAt)
return this.Query(tx). err := this.Query(tx).
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId, "clusterId": clusterId,
"role": role, "role": role,
@@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
}, maps.Map{ }, maps.Map{
"value": valueJSON, "value": valueJSON,
}) })
if err != nil {
return err
}
// 触发钩子
err = this.nodeValueHook(tx, role, nodeId, item, valueJSON)
if err != nil {
return err
}
return nil
} }
// Clean 清除数据 // Clean 清除数据
@@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI
// FindLatestNodeValue 获取最近一条数据 // FindLatestNodeValue 获取最近一条数据
func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) { func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) {
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60)) var fromMinute = timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60))
one, err := this.Query(tx). one, err := this.Query(tx).
Attr("role", role). Attr("role", role).

View File

@@ -0,0 +1,14 @@
// Copyright 2023 Liuxiangchao iwind.liu@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"
)
// 节点值变更Hook
func (this *NodeValueDAO) nodeValueHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64, item nodeconfigs.NodeValueItem, valueJSON []byte) error {
return nil
}

View File

@@ -24,6 +24,7 @@ type NSCluster struct {
SoaSerial uint64 `field:"soaSerial"` // SOA序列号 SoaSerial uint64 `field:"soaSerial"` // SOA序列号
Email string `field:"email"` // 管理员邮箱 Email string `field:"email"` // 管理员邮箱
DetectAgents bool `field:"detectAgents"` // 是否监测Agents DetectAgents bool `field:"detectAgents"` // 是否监测Agents
CheckingPorts bool `field:"checkingPorts"` // 自动检测端口
} }
type NSClusterOperator struct { type NSClusterOperator struct {
@@ -47,6 +48,7 @@ type NSClusterOperator struct {
SoaSerial any // SOA序列号 SoaSerial any // SOA序列号
Email any // 管理员邮箱 Email any // 管理员邮箱
DetectAgents any // 是否监测Agents DetectAgents any // 是否监测Agents
CheckingPorts any // 自动检测端口
} }
func NewNSClusterOperator() *NSClusterOperator { func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -275,8 +275,66 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
return this.NotifyUpdate(tx, originId) return this.NotifyUpdate(tx, originId)
} }
// CloneOrigin 复制源站
func (this *OriginDAO) CloneOrigin(tx *dbs.Tx, fromOriginId int64) (newOriginId int64, err error) {
if fromOriginId <= 0 {
return
}
originOne, err := this.Find(tx, fromOriginId)
if err != nil || originOne == nil {
return
}
var origin = originOne.(*Origin)
var op = NewOriginOperator()
op.IsOn = origin.IsOn
op.Name = origin.Name
op.Version = origin.Version
if IsNotNull(origin.Addr) {
op.Addr = origin.Addr
}
op.Description = origin.Description
op.Code = origin.Code
op.Weight = origin.Weight
if IsNotNull(origin.ConnTimeout) {
op.ConnTimeout = origin.ConnTimeout
}
if IsNotNull(origin.ReadTimeout) {
op.ReadTimeout = origin.ReadTimeout
}
if IsNotNull(origin.IdleTimeout) {
op.IdleTimeout = origin.IdleTimeout
}
op.MaxFails = origin.MaxFails
op.MaxConns = origin.MaxConns
op.MaxIdleConns = origin.MaxIdleConns
op.HttpRequestURI = origin.HttpRequestURI
if IsNotNull(origin.HttpRequestHeader) {
op.HttpRequestHeader = origin.HttpRequestHeader
}
if IsNotNull(origin.HttpResponseHeader) {
op.HttpResponseHeader = origin.HttpResponseHeader
}
op.Host = origin.Host
if IsNotNull(origin.HealthCheck) {
op.HealthCheck = origin.HealthCheck
}
if IsNotNull(origin.Cert) {
// TODO 需要Clone证书
op.Cert = origin.Cert
}
if IsNotNull(origin.Ftp) {
op.Ftp = origin.Ftp
}
if IsNotNull(origin.Domains) {
op.Domains = origin.Domains
}
op.FollowPort = origin.FollowPort
op.State = origin.State
return this.SaveInt64(tx, op)
}
// ComposeOriginConfig 将源站信息转换为配置 // ComposeOriginConfig 将源站信息转换为配置
func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap *utils.CacheMap) (*serverconfigs.OriginConfig, error) { func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.OriginConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -403,7 +461,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
config.CertRef = ref config.CertRef = ref
if ref.CertId > 0 { if ref.CertId > 0 {
certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, false, cacheMap) certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, false, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -8,7 +8,7 @@ import (
func TestOriginServerDAO_ComposeOriginConfig(t *testing.T) { func TestOriginServerDAO_ComposeOriginConfig(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
config, err := SharedOriginDAO.ComposeOriginConfig(tx, 1, nil) config, err := SharedOriginDAO.ComposeOriginConfig(tx, 1, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -122,7 +122,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionProvinceStateEnabled). State(RegionProvinceStateEnabled).
Attr("countryId", countryId). Attr("countryId", countryId).
Asc(). AscPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
@@ -132,7 +132,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) { func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionProvinceStateEnabled). State(RegionProvinceStateEnabled).
Asc(). AscPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
return return

View File

@@ -81,7 +81,7 @@ func (this *ReverseProxyDAO) FindEnabledReverseProxy(tx *dbs.Tx, id int64) (*Rev
} }
// ComposeReverseProxyConfig 根据ID组合配置 // ComposeReverseProxyConfig 根据ID组合配置
func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyId int64, cacheMap *utils.CacheMap) (*serverconfigs.ReverseProxyConfig, error) { func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyId int64, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.ReverseProxyConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -125,7 +125,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, err return nil, err
} }
for _, ref := range originRefs { for _, ref := range originRefs {
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, cacheMap) originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -142,7 +142,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, err return nil, err
} }
for _, ref := range originRefs { for _, ref := range originRefs {
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, cacheMap) originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -243,6 +243,115 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
return types.Int64(op.Id), nil return types.Int64(op.Id), nil
} }
// CloneReverseProxy 复制反向代理
func (this *ReverseProxyDAO) CloneReverseProxy(tx *dbs.Tx, fromReverseProxyId int64) (newReverseProxyId int64, err error) {
if fromReverseProxyId <= 0 {
return
}
reverseProxyOne, err := this.Query(tx).
Pk(fromReverseProxyId).
State(ReverseProxyStateEnabled).
Find()
if err != nil || reverseProxyOne == nil {
return 0, err
}
var reverseProxy = reverseProxyOne.(*ReverseProxy)
var op = NewReverseProxyOperator()
op.TemplateId = reverseProxy.TemplateId
op.IsOn = reverseProxy.IsOn
if IsNotNull(reverseProxy.Scheduling) {
op.Scheduling = reverseProxy.Scheduling
}
if IsNotNull(reverseProxy.PrimaryOrigins) {
var originRefs = []*serverconfigs.OriginRef{}
err = json.Unmarshal(reverseProxy.PrimaryOrigins, &originRefs)
if err != nil {
return 0, err
}
var newRefs = []*serverconfigs.OriginRef{}
for _, originRef := range originRefs {
if originRef.OriginId > 0 {
newOriginId, err := SharedOriginDAO.CloneOrigin(tx, originRef.OriginId)
if err != nil {
return 0, err
}
if newOriginId > 0 {
newRef, err := utils.JSONClone[*serverconfigs.OriginRef](originRef)
if err != nil {
return 0, err
}
newRef.OriginId = newOriginId
newRefs = append(newRefs, newRef)
}
}
}
newRefsJSON, err := json.Marshal(newRefs)
if err != nil {
return 0, err
}
op.PrimaryOrigins = newRefsJSON
}
if IsNotNull(reverseProxy.BackupOrigins) {
var originRefs = []*serverconfigs.OriginRef{}
err = json.Unmarshal(reverseProxy.BackupOrigins, &originRefs)
if err != nil {
return 0, err
}
var newRefs = []*serverconfigs.OriginRef{}
for _, originRef := range originRefs {
if originRef.OriginId > 0 {
newOriginId, err := SharedOriginDAO.CloneOrigin(tx, originRef.OriginId)
if err != nil {
return 0, err
}
if newOriginId > 0 {
newRef, err := utils.JSONClone[*serverconfigs.OriginRef](originRef)
if err != nil {
return 0, err
}
newRef.OriginId = newOriginId
newRefs = append(newRefs, newRef)
}
}
}
newRefsJSON, err := json.Marshal(newRefs)
if err != nil {
return 0, err
}
op.BackupOrigins = newRefsJSON
}
op.StripPrefix = reverseProxy.StripPrefix
op.RequestHostType = reverseProxy.RequestHostType
op.RequestHost = reverseProxy.RequestHost
op.RequestHostExcludingPort = reverseProxy.RequestHostExcludingPort
op.RequestURI = reverseProxy.RequestURI
op.AutoFlush = reverseProxy.AutoFlush
if IsNotNull(reverseProxy.AddHeaders) {
// TODO 复制Header
op.AddHeaders = reverseProxy.AddHeaders
}
op.State = reverseProxy.State
if IsNotNull(reverseProxy.ConnTimeout) {
op.ConnTimeout = reverseProxy.ConnTimeout
}
if IsNotNull(reverseProxy.ReadTimeout) {
op.ReadTimeout = reverseProxy.ReadTimeout
}
if IsNotNull(reverseProxy.IdleTimeout) {
op.IdleTimeout = reverseProxy.IdleTimeout
}
op.MaxConns = reverseProxy.MaxConns
op.MaxIdleConns = reverseProxy.MaxIdleConns
if IsNotNull(reverseProxy.ProxyProtocol) {
op.ProxyProtocol = reverseProxy.ProxyProtocol
}
op.FollowRedirects = reverseProxy.FollowRedirects
return this.SaveInt64(tx, op)
}
// UpdateReverseProxyScheduling 修改反向代理调度算法 // UpdateReverseProxyScheduling 修改反向代理调度算法
func (this *ReverseProxyDAO) UpdateReverseProxyScheduling(tx *dbs.Tx, reverseProxyId int64, schedulingJSON []byte) error { func (this *ReverseProxyDAO) UpdateReverseProxyScheduling(tx *dbs.Tx, reverseProxyId int64, schedulingJSON []byte) error {
if reverseProxyId <= 0 { if reverseProxyId <= 0 {

View File

@@ -8,7 +8,7 @@ import (
func TestReverseProxyDAO_ComposeReverseProxyConfig(t *testing.T) { func TestReverseProxyDAO_ComposeReverseProxyConfig(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
config, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, 1, nil) config, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, 1, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -63,7 +64,7 @@ func init() {
// UpdateServerBandwidth 写入数据 // UpdateServerBandwidth 写入数据
// 暂时不使用region区分 // 暂时不使用region区分
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, day string, timeAt string, bytes int64, totalBytes int64) error { 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 {
if serverId <= 0 { if serverId <= 0 {
return errors.New("invalid server id '" + types.String(serverId) + "'") return errors.New("invalid server id '" + types.String(serverId) + "'")
} }
@@ -72,18 +73,34 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
Table(this.partialTable(serverId)). Table(this.partialTable(serverId)).
Param("bytes", bytes). Param("bytes", bytes).
Param("totalBytes", totalBytes). Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"userId": userId, "userId": userId,
"serverId": serverId, "serverId": serverId,
"day": day, "regionId": regionId,
"timeAt": timeAt, "day": day,
"bytes": bytes, "timeAt": timeAt,
"totalBytes": totalBytes, "bytes": bytes,
"avgBytes": totalBytes / 300, "totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
"attackBytes": attackBytes,
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
}, maps.Map{ }, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"), "bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题 "avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+: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"),
}) })
} }
@@ -110,6 +127,7 @@ func (this *ServerBandwidthStatDAO) FindHourlyBandwidthStats(tx *dbs.Tx, serverI
ones, _, err := this.Query(tx). ones, _, err := this.Query(tx).
Table(this.partialTable(serverId)). Table(this.partialTable(serverId)).
Between("day", timeutil.FormatTime("Ymd", timestamp), timeutil.Format("Ymd")).
Attr("serverId", serverId). Attr("serverId", serverId).
Result(this.maxBytesField(useAvg), "CONCAT(day, '.', SUBSTRING(timeAt, 1, 2)) AS fullTime"). Result(this.maxBytesField(useAvg), "CONCAT(day, '.', SUBSTRING(timeAt, 1, 2)) AS fullTime").
Gte("CONCAT(day, '.', SUBSTRING(timeAt, 1, 2))", timeutil.FormatTime("Ymd.H", timestamp)). Gte("CONCAT(day, '.', SUBSTRING(timeAt, 1, 2))", timeutil.FormatTime("Ymd.H", timestamp)).
@@ -509,6 +527,7 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
// 总数量 // 总数量
total, err := this.Query(tx). total, err := this.Query(tx).
Table(this.partialTable(serverId)). Table(this.partialTable(serverId)).
Between("day", timeFrom[:8], timeTo[:8]).
Attr("serverId", serverId). Attr("serverId", serverId).
Between("CONCAT(day, timeAt)", timeFrom, timeTo). Between("CONCAT(day, timeAt)", timeFrom, timeTo).
Count() Count()
@@ -528,6 +547,7 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
// 查询 nth 位置 // 查询 nth 位置
one, err := this.Query(tx). one, err := this.Query(tx).
Table(this.partialTable(serverId)). Table(this.partialTable(serverId)).
Between("day", timeFrom[:8], timeTo[:8]).
Attr("serverId", serverId). Attr("serverId", serverId).
Between("CONCAT(day, timeAt)", timeFrom, timeTo). Between("CONCAT(day, timeAt)", timeFrom, timeTo).
Desc(this.bytesOrderField(useAvg)). Desc(this.bytesOrderField(useAvg)).
@@ -540,6 +560,191 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
return this.fixServerStat(one.(*ServerBandwidthStat), useAvg), nil return this.fixServerStat(one.(*ServerBandwidthStat), useAvg), nil
} }
// FindDailyStats 按天统计
func (this *ServerBandwidthStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerBandwidthStat, err error) {
// 兼容以往版本
if !regexputils.YYYYMMDD.MatchString(dayFrom) || !regexputils.YYYYMMDD.MatchString(dayTo) {
return nil, nil
}
hasFullData, err := this.HasFullData(tx, serverId, dayFrom[:6])
if err != nil {
return nil, err
}
if !hasFullData {
ones, err := SharedServerDailyStatDAO.compatFindDailyStats(tx, serverId, dayFrom, dayTo)
if err != nil {
return nil, err
}
for _, one := range ones {
result = append(result, one.AsServerBandwidthStat())
}
return result, nil
}
ones, err := this.Query(tx).
Table(this.partialTable(serverId)).
Result("SUM(totalBytes) AS totalBytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day").
Attr("serverId", serverId).
Between("day", dayFrom, dayTo).
Group("day").
FindAll()
if err != nil {
return nil, err
}
var dayMap = map[string]*ServerBandwidthStat{} // day => Stat
for _, one := range ones {
var stat = one.(*ServerBandwidthStat)
dayMap[stat.Day] = stat
}
days, err := utils.RangeDays(dayFrom, dayTo)
if err != nil {
return nil, err
}
for _, day := range days {
stat, ok := dayMap[day]
if ok {
result = append(result, stat)
} else {
result = append(result, &ServerBandwidthStat{Day: day})
}
}
return
}
// FindHourlyStats 按小时统计
func (this *ServerBandwidthStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hourFrom string, hourTo string) (result []*ServerBandwidthStat, err error) {
// 兼容以往版本
if !regexputils.YYYYMMDDHH.MatchString(hourFrom) || !regexputils.YYYYMMDDHH.MatchString(hourTo) {
return nil, nil
}
hasFullData, err := this.HasFullData(tx, serverId, hourFrom[:6])
if err != nil {
return nil, err
}
if !hasFullData {
ones, err := SharedServerDailyStatDAO.compatFindHourlyStats(tx, serverId, hourFrom, hourTo)
if err != nil {
return nil, err
}
for _, one := range ones {
result = append(result, one.AsServerBandwidthStat())
}
return result, nil
}
var query = this.Query(tx).
Table(this.partialTable(serverId)).
Between("day", hourFrom[:8], hourTo[:8]).
Result("MIN(day) AS day", "MIN(timeAt) AS timeAt", "SUM(totalBytes) AS totalBytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "CONCAT(day, SUBSTR(timeAt, 1, 2)) AS hour").
Attr("serverId", serverId)
if hourFrom[:8] == hourTo[:8] { // 同一天
query.Attr("day", hourFrom[:8])
query.Between("timeAt", hourFrom[8:]+"00", hourTo[8:]+"59")
} else {
query.Between("CONCAT(day, SUBSTR(timeAt, 1, 2))", hourFrom, hourTo)
}
ones, err := query.
Group("hour").
FindAll()
if err != nil {
return nil, err
}
var hourMap = map[string]*ServerBandwidthStat{} // hour => Stat
for _, one := range ones {
var stat = one.(*ServerBandwidthStat)
var hour = stat.Day + stat.TimeAt[:2]
hourMap[hour] = stat
}
hours, err := utils.RangeHours(hourFrom, hourTo)
if err != nil {
return nil, err
}
for _, hour := range hours {
stat, ok := hourMap[hour]
if ok {
result = append(result, stat)
} else {
result = append(result, &ServerBandwidthStat{
Day: hour[:8],
TimeAt: hour[8:] + "00",
})
}
}
return
}
// SumDailyStat 获取某天内的流量
// dayFrom 格式为YYYYMMDD
// dayTo 格式为YYYYMMDD
func (this *ServerBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, regionId int64, dayFrom string, dayTo string) (stat *pb.ServerDailyStat, err error) {
if !regexputils.YYYYMMDD.MatchString(dayFrom) {
return nil, errors.New("invalid dayFrom '" + dayFrom + "'")
}
if !regexputils.YYYYMMDD.MatchString(dayTo) {
return nil, errors.New("invalid dayTo '" + dayTo + "'")
}
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, serverId, dayFrom[:6])
if err != nil {
return nil, err
}
if !hasFullData {
return SharedServerDailyStatDAO.compatSumDailyStat(tx, 0, serverId, regionId, dayFrom, dayTo)
}
stat = &pb.ServerDailyStat{}
if serverId <= 0 {
return
}
if dayFrom > dayTo {
dayFrom, dayTo = dayTo, dayFrom
}
var query = this.Query(tx).
Table(this.partialTable(serverId)).
Result("SUM(totalBytes) AS totalBytes, SUM(cachedBytes) AS cachedBytes, SUM(countRequests) AS countRequests, SUM(countCachedRequests) AS countCachedRequests, SUM(countAttackRequests) AS countAttackRequests, SUM(attackBytes) AS attackBytes")
query.Attr("serverId", serverId)
if regionId > 0 {
query.Attr("regionId", regionId)
}
if dayFrom == dayTo {
query.Attr("day", dayFrom)
} else {
query.Between("day", dayFrom, dayTo)
}
one, _, err := query.FindOne()
if err != nil {
return nil, err
}
if one == nil {
return
}
stat.Bytes = one.GetInt64("totalBytes")
stat.CachedBytes = one.GetInt64("cachedBytes")
stat.CountRequests = one.GetInt64("countRequests")
stat.CountCachedRequests = one.GetInt64("countCachedRequests")
stat.CountAttackRequests = one.GetInt64("countAttackRequests")
stat.AttackBytes = one.GetInt64("attackBytes")
return
}
// Clean 清理过期数据 // Clean 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error { func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据 var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据
@@ -619,3 +824,50 @@ func (this *ServerBandwidthStatDAO) fixServerStats(stats []*ServerBandwidthStat,
} }
} }
} }
// HasFullData 检查一个月是否完整数据
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
func (this *ServerBandwidthStatDAO) HasFullData(tx *dbs.Tx, serverId int64, month string) (bool, error) {
var monthKey = month + "@" + types.String(serverId)
if !regexputils.YYYYMM.MatchString(month) {
return false, errors.New("invalid month '" + month + "'")
}
fullDataLocker.Lock()
hasData, ok := fullDataMap[monthKey]
fullDataLocker.Unlock()
if ok {
return hasData, nil
}
var year = types.Int(month[:4])
var monthInt = types.Int(month[4:])
if year < 2000 || monthInt > 12 || monthInt < 1 {
return false, nil
}
var lastMonth = monthInt - 1
if lastMonth == 0 {
lastMonth = 12
year--
}
var lastMonthString = fmt.Sprintf("%d%02d", year, lastMonth)
one, err := this.Query(tx).
Table(this.partialTable(serverId)).
Between("day", lastMonthString+"01", lastMonthString+"31").
DescPk().
Find()
if err != nil {
return false, err
}
var b = one != nil && one.(*ServerBandwidthStat).CountRequests > 0
fullDataLocker.Lock()
fullDataMap[monthKey] = b
fullDataLocker.Unlock()
return b, nil
}

View File

@@ -16,7 +16,7 @@ import (
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) { func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO() var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, 1, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300) 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)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -28,9 +28,12 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
var count = 1 // 测试时将此值设为一个比较大的数字 var count = 1 // 测试时将此值设为一个比较大的数字
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if i%10000 == 0 {
t.Log(i)
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200))) 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)) var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
err := dao.UpdateServerBandwidth(tx, 1, 1, day, minute, 1024, 300) err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -2,27 +2,37 @@ package models
// ServerBandwidthStat 服务峰值带宽统计 // ServerBandwidthStat 服务峰值带宽统计
type ServerBandwidthStat struct { type ServerBandwidthStat struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID ServerId uint64 `field:"serverId"` // 服务ID
RegionId uint32 `field:"regionId"` // 区域ID RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节 Bytes uint64 `field:"bytes"` // 带宽字节
AvgBytes uint64 `field:"avgBytes"` // 平均流量 AvgBytes uint64 `field:"avgBytes"` // 平均流量
TotalBytes uint64 `field:"totalBytes"` // 流量 CachedBytes uint64 `field:"cachedBytes"` // 缓存的流量
AttackBytes uint64 `field:"attackBytes"` // 攻击流量
CountRequests uint64 `field:"countRequests"` // 请求数
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
CountAttackRequests uint64 `field:"countAttackRequests"` // 攻击请求数
TotalBytes uint64 `field:"totalBytes"` // 总流量
} }
type ServerBandwidthStatOperator struct { type ServerBandwidthStatOperator struct {
Id any // ID Id any // ID
UserId any // 用户ID UserId any // 用户ID
ServerId any // 服务ID ServerId any // 服务ID
RegionId any // 区域ID RegionId any // 区域ID
Day any // 日期YYYYMMDD Day any // 日期YYYYMMDD
TimeAt any // 时间点HHMM TimeAt any // 时间点HHMM
Bytes any // 带宽字节 Bytes any // 带宽字节
AvgBytes any // 平均流量 AvgBytes any // 平均流量
TotalBytes any // 流量 CachedBytes any // 缓存的流量
AttackBytes any // 攻击流量
CountRequests any // 请求数
CountCachedRequests any // 缓存的请求数
CountAttackRequests any // 攻击请求数
TotalBytes any // 总流量
} }
func NewServerBandwidthStatOperator() *ServerBandwidthStatOperator { func NewServerBandwidthStatOperator() *ServerBandwidthStatOperator {

View File

@@ -61,19 +61,24 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
var serverUserMap = map[int64]int64{} // serverId => userId var serverUserMap = map[int64]int64{} // serverId => userId
var cacheMap = utils.NewCacheMap() var cacheMap = utils.NewCacheMap()
for _, stat := range stats { for _, stat := range stats {
day := timeutil.FormatTime("Ymd", stat.CreatedAt) var day = timeutil.FormatTime("Ymd", stat.CreatedAt)
hour := timeutil.FormatTime("YmdH", stat.CreatedAt) var hour = timeutil.FormatTime("YmdH", stat.CreatedAt)
timeFrom := timeutil.FormatTime("His", stat.CreatedAt) var timeFrom = timeutil.FormatTime("His", stat.CreatedAt)
timeTo := timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟 var timeTo = timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟
// 所属用户 // 用户ID
serverUserId, ok := serverUserMap[stat.ServerId] var serverUserId = stat.UserId
if !ok { if serverUserId == 0 {
userId, err := SharedServerDAO.FindServerUserId(tx, stat.ServerId) var ok bool
if err != nil { serverUserId, ok = serverUserMap[stat.ServerId]
return err if !ok {
userId, err := SharedServerDAO.FindServerUserId(tx, stat.ServerId)
if err != nil {
return err
}
serverUserMap[stat.ServerId] = userId
serverUserId = userId
} }
serverUserId = userId
} }
_, _, err := this.Query(tx). _, _, err := this.Query(tx).
@@ -195,7 +200,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, reg
// SumUserDaily 获取某天流量总和 // SumUserDaily 获取某天流量总和
// day 格式为YYYYMMDD // day 格式为YYYYMMDD
func (this *ServerDailyStatDAO) SumUserDaily(tx *dbs.Tx, userId int64, regionId int64, day string) (stat *ServerDailyStat, err error) { func (this *ServerDailyStatDAO) compatSumUserDaily(tx *dbs.Tx, userId int64, regionId int64, day string) (stat *ServerDailyStat, err error) {
var query = this.Query(tx) var query = this.Query(tx)
if regionId > 0 { if regionId > 0 {
query.Attr("regionId", regionId) query.Attr("regionId", regionId)
@@ -234,7 +239,7 @@ func (this *ServerDailyStatDAO) SumUserTrafficBytesBetweenDays(tx *dbs.Tx, userI
// SumUserMonthly 获取某月流量总和 // SumUserMonthly 获取某月流量总和
// month 格式为YYYYMM // month 格式为YYYYMM
func (this *ServerDailyStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, month string) (int64, error) { func (this *ServerDailyStatDAO) compatSumUserMonthly(tx *dbs.Tx, userId int64, month string) (int64, error) {
return this.Query(tx). return this.Query(tx).
Between("day", month+"01", month+"31"). Between("day", month+"01", month+"31").
Attr("userId", userId). Attr("userId", userId).
@@ -323,10 +328,10 @@ func (this *ServerDailyStatDAO) SumHourlyStat(tx *dbs.Tx, serverId int64, hour s
return return
} }
// SumDailyStat 获取某天内的流量 // compatSumDailyStat 获取某天内的流量
// dayFrom 格式为YYYYMMDD // dayFrom 格式为YYYYMMDD
// dayTo 格式为YYYYMMDD // dayTo 格式为YYYYMMDD
func (this *ServerDailyStatDAO) SumDailyStat(tx *dbs.Tx, userId int64, serverId int64, regionId int64, dayFrom string, dayTo string) (stat *pb.ServerDailyStat, err error) { func (this *ServerDailyStatDAO) compatSumDailyStat(tx *dbs.Tx, userId int64, serverId int64, regionId int64, dayFrom string, dayTo string) (stat *pb.ServerDailyStat, err error) {
stat = &pb.ServerDailyStat{} stat = &pb.ServerDailyStat{}
if userId <= 0 && serverId <= 0 { if userId <= 0 && serverId <= 0 {
@@ -463,7 +468,7 @@ func (this *ServerDailyStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, mont
} }
// FindDailyStats 按天统计 // FindDailyStats 按天统计
func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) { func (this *ServerDailyStatDAO) compatFindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) {
ones, err := this.Query(tx). ones, err := this.Query(tx).
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day"). Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day").
Attr("serverId", serverId). Attr("serverId", serverId).
@@ -476,7 +481,7 @@ func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFr
dayMap := map[string]*ServerDailyStat{} // day => Stat dayMap := map[string]*ServerDailyStat{} // day => Stat
for _, one := range ones { for _, one := range ones {
stat := one.(*ServerDailyStat) var stat = one.(*ServerDailyStat)
dayMap[stat.Day] = stat dayMap[stat.Day] = stat
} }
days, err := utils.RangeDays(dayFrom, dayTo) days, err := utils.RangeDays(dayFrom, dayTo)
@@ -640,7 +645,7 @@ func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month strin
} }
// FindHourlyStats 按小时统计 // FindHourlyStats 按小时统计
func (this *ServerDailyStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hourFrom string, hourTo string) (result []*ServerDailyStat, err error) { func (this *ServerDailyStatDAO) compatFindHourlyStats(tx *dbs.Tx, serverId int64, hourFrom string, hourTo string) (result []*ServerDailyStat, err error) {
ones, err := this.Query(tx). ones, err := this.Query(tx).
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "hour"). Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "hour").
Attr("serverId", serverId). Attr("serverId", serverId).
@@ -651,9 +656,11 @@ func (this *ServerDailyStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hour
return nil, err return nil, err
} }
hourMap := map[string]*ServerDailyStat{} // hour => Stat var hourMap = map[string]*ServerDailyStat{} // hour => Stat
for _, one := range ones { for _, one := range ones {
stat := one.(*ServerDailyStat) var stat = one.(*ServerDailyStat)
stat.Day = stat.Hour[:8]
stat.TimeFrom = stat.Hour[8:] + "00"
hourMap[stat.Hour] = stat hourMap[stat.Hour] = stat
} }
hours, err := utils.RangeHours(hourFrom, hourTo) hours, err := utils.RangeHours(hourFrom, hourTo)
@@ -665,7 +672,11 @@ func (this *ServerDailyStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hour
if ok { if ok {
result = append(result, stat) result = append(result, stat)
} else { } else {
result = append(result, &ServerDailyStat{Hour: hour}) result = append(result, &ServerDailyStat{
Hour: hour,
Day: hour[:8],
TimeFrom: hour[8:] + "00",
})
} }
} }

View File

@@ -1,10 +1,13 @@
package models package models_test
import ( import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"testing" "testing"
"time" "time"
@@ -12,7 +15,7 @@ import (
func TestServerDailyStatDAO_SaveStats(t *testing.T) { func TestServerDailyStatDAO_SaveStats(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
stats := []*pb.ServerDailyStat{ var stats = []*pb.ServerDailyStat{
{ {
ServerId: 1, ServerId: 1,
NodeRegionId: 2, NodeRegionId: 2,
@@ -20,7 +23,7 @@ func TestServerDailyStatDAO_SaveStats(t *testing.T) {
CreatedAt: 1607671488, CreatedAt: 1607671488,
}, },
} }
err := NewServerDailyStatDAO().SaveStats(tx, stats) err := models.NewServerDailyStatDAO().SaveStats(tx, stats)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -29,7 +32,7 @@ func TestServerDailyStatDAO_SaveStats(t *testing.T) {
func TestServerDailyStatDAO_SaveStats2(t *testing.T) { func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
stats := []*pb.ServerDailyStat{ var stats = []*pb.ServerDailyStat{
{ {
ServerId: 1, ServerId: 1,
NodeRegionId: 3, NodeRegionId: 3,
@@ -37,7 +40,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
CreatedAt: 1607671488, CreatedAt: 1607671488,
}, },
} }
err := NewServerDailyStatDAO().SaveStats(tx, stats) err := models.NewServerDailyStatDAO().SaveStats(tx, stats)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -47,7 +50,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) { func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
bytes, err := NewServerDailyStatDAO().SumUserMonthly(tx, 1, timeutil.Format("Ym")) bytes, err := models.NewUserBandwidthStatDAO().SumUserMonthly(tx, 1, timeutil.Format("Ym"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -58,7 +61,7 @@ func TestServerDailyStatDAO_SumHourlyRequests(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
stat, err := NewServerDailyStatDAO().SumHourlyStat(tx, 23, timeutil.Format("YmdH")) stat, err := models.NewServerDailyStatDAO().SumHourlyStat(tx, 23, timeutil.Format("YmdH"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -69,7 +72,7 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
stat, err := NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd")+"1435") stat, err := models.NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd")+"1435")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -78,7 +81,7 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) { func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
serverIds, err := NewServerDailyStatDAO().FindDistinctServerIds(tx, timeutil.Format("Ym01"), timeutil.Format("Ymd")) serverIds, err := models.NewServerDailyStatDAO().FindDistinctServerIds(tx, timeutil.Format("Ym01"), timeutil.Format("Ymd"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -87,7 +90,7 @@ func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
func TestServerDailyStatDAO_FindStatsBetweenDays(t *testing.T) { func TestServerDailyStatDAO_FindStatsBetweenDays(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
stats, err := NewServerDailyStatDAO().FindStatsBetweenDays(tx, 1, 0, 0, timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)), timeutil.Format("Ymd")) stats, err := models.NewServerDailyStatDAO().FindStatsBetweenDays(tx, 1, 0, 0, timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)), timeutil.Format("Ymd"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -96,8 +99,41 @@ func TestServerDailyStatDAO_FindStatsBetweenDays(t *testing.T) {
} }
} }
func TestSeverDailyStatDAO_InsertMany(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
var dao = models.NewServerDailyStatDAO()
var count = 1 // 实际测试时可以将此值调的很大
for i := 0; i < count; i++ {
if i%10000 == 0 {
t.Log(i)
}
err := dao.SaveStats(tx, []*pb.ServerDailyStat{{
ServerId: 23,
NodeRegionId: int64(rands.Int(0, 999999)),
Bytes: 1024,
CachedBytes: 1024,
CountRequests: 1024,
CountCachedRequests: 1024,
CreatedAt: time.Now().Unix(),
CountAttackRequests: 1024,
AttackBytes: 1024,
CheckTrafficLimiting: false,
PlanId: 0,
Day: "202303" + fmt.Sprintf("%02d", rands.Int(1, 31)),
Hour: "2023032101",
TimeFrom: fmt.Sprintf("%06d", rands.Int(0, 999999)),
TimeTo: "211459",
}})
if err != nil {
t.Fatal(err)
}
}
}
func TestServerDailyStatDAO_FindStatsWithDay(t *testing.T) { func TestServerDailyStatDAO_FindStatsWithDay(t *testing.T) {
var dao = NewServerDailyStatDAO() var dao = models.NewServerDailyStatDAO()
var tx *dbs.Tx var tx *dbs.Tx
stats, err := dao.FindStatsWithDay(tx, 23, timeutil.Format("Ymd"), "000000", "235900") stats, err := dao.FindStatsWithDay(tx, 23, timeutil.Format("Ymd"), "000000", "235900")
if err != nil { if err != nil {

View File

@@ -1 +1,50 @@
package models package models
func (this *ServerDailyStat) AsUserBandwidthStat() *UserBandwidthStat {
var timeAt = "0000"
if len(this.TimeFrom) >= 4 {
timeAt = this.TimeFrom[:4]
} else if len(this.Hour) > 8 {
timeAt = this.Hour[8:] + "00"
}
return &UserBandwidthStat{
Id: 0,
UserId: uint64(this.UserId),
RegionId: this.RegionId,
Day: this.Day,
TimeAt: timeAt,
Bytes: this.Bytes / 300,
TotalBytes: this.Bytes,
AvgBytes: this.Bytes / 300,
CachedBytes: this.CachedBytes,
AttackBytes: this.AttackBytes,
CountRequests: this.CountRequests,
CountCachedRequests: this.CountCachedRequests,
CountAttackRequests: this.CountAttackRequests,
}
}
func (this *ServerDailyStat) AsServerBandwidthStat() *ServerBandwidthStat {
var timeAt = "0000"
if len(this.TimeFrom) >= 4 {
timeAt = this.TimeFrom[:4]
} else if len(this.Hour) > 8 {
timeAt = this.Hour[8:] + "00"
}
return &ServerBandwidthStat{
Id: 0,
UserId: uint64(this.UserId),
ServerId: uint64(this.ServerId),
RegionId: this.RegionId,
Day: this.Day,
TimeAt: timeAt,
Bytes: this.Bytes / 300,
TotalBytes: this.Bytes,
AvgBytes: this.Bytes / 300,
CachedBytes: this.CachedBytes,
AttackBytes: this.AttackBytes,
CountRequests: this.CountRequests,
CountCachedRequests: this.CountCachedRequests,
CountAttackRequests: this.CountAttackRequests,
}
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -31,6 +32,10 @@ const (
ServerStateDisabled = 0 // 已禁用 ServerStateDisabled = 0 // 已禁用
) )
const (
ModelServerNameMaxLength = 60
)
type ServerDAO dbs.DAO type ServerDAO dbs.DAO
func NewServerDAO() *ServerDAO { func NewServerDAO() *ServerDAO {
@@ -121,7 +126,7 @@ func (this *ServerDAO) FindEnabledServerBasic(tx *dbs.Tx, serverId int64) (*Serv
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(serverId). Pk(serverId).
State(ServerStateEnabled). State(ServerStateEnabled).
Result("id", "name", "description", "isOn", "type", "clusterId", "userId"). Result("id", "name", "description", "isOn", "type", "clusterId", "userId", "groupIds").
Find() Find()
if result == nil { if result == nil {
return nil, err return nil, err
@@ -205,6 +210,15 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
if IsNotNull(udpJSON) { if IsNotNull(udpJSON) {
op.Udp = udpJSON op.Udp = udpJSON
} }
// 如果没有Web配置则创建之
if webId <= 0 {
webId, err = SharedHTTPWebDAO.CreateWeb(tx, 0, userId, nil)
if err != nil {
return 0, err
}
}
op.WebId = webId op.WebId = webId
if IsNotNull(reverseProxyJSON) { if IsNotNull(reverseProxyJSON) {
op.ReverseProxy = reverseProxyJSON op.ReverseProxy = reverseProxyJSON
@@ -783,9 +797,11 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
} }
if userId > 0 { if userId > 0 {
query.Attr("userId", userId) query.Attr("userId", userId)
query.UseIndex("userId")
} }
if clusterId > 0 { if clusterId > 0 {
query.Attr("clusterId", clusterId) query.Attr("clusterId", clusterId)
query.UseIndex("clusterId")
} }
if auditingFlag == configutils.BoolStateYes { if auditingFlag == configutils.BoolStateYes {
query.Attr("isAuditing", true) query.Attr("isAuditing", true)
@@ -839,9 +855,11 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
} }
if userId > 0 { if userId > 0 {
query.Attr("userId", userId) query.Attr("userId", userId)
query.UseIndex("userId")
} }
if clusterId > 0 { if clusterId > 0 {
query.Attr("clusterId", clusterId) query.Attr("clusterId", clusterId)
query.UseIndex("clusterId")
} }
if auditingFlag == 1 { if auditingFlag == 1 {
query.Attr("isAuditing", true) query.Attr("isAuditing", true)
@@ -1009,12 +1027,12 @@ func (this *ServerDAO) ComposeServerConfigWithServerId(tx *dbs.Tx, serverId int6
if server == nil { if server == nil {
return nil, ErrNotFound return nil, ErrNotFound
} }
return this.ComposeServerConfig(tx, server, ignoreCertData, nil, forNode, false) return this.ComposeServerConfig(tx, server, ignoreCertData, nil, nil, forNode, false)
} }
// ComposeServerConfig 构造服务的Config // ComposeServerConfig 构造服务的Config
// forNode 是否是节点请求 // forNode 是否是节点请求
func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCerts bool, cacheMap *utils.CacheMap, forNode bool, forList bool) (*serverconfigs.ServerConfig, error) { func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCerts bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap, forNode bool, forList bool) (*serverconfigs.ServerConfig, error) {
if server == nil { if server == nil {
return nil, ErrNotFound return nil, ErrNotFound
} }
@@ -1034,12 +1052,14 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
config.UserId = int64(server.UserId) config.UserId = int64(server.UserId)
config.Type = server.Type config.Type = server.Type
config.IsOn = server.IsOn config.IsOn = server.IsOn
config.Name = server.Name if !forNode {
config.Description = server.Description config.Name = server.Name
config.Description = server.Description
}
var groupConfig *serverconfigs.ServerGroupConfig var groupConfig *serverconfigs.ServerGroupConfig
for _, groupId := range server.DecodeGroupIds() { for _, groupId := range server.DecodeGroupIds() {
groupConfig1, err := SharedServerGroupDAO.ComposeGroupConfig(tx, groupId, forList, cacheMap) groupConfig1, err := SharedServerGroupDAO.ComposeGroupConfig(tx, groupId, forNode, forList, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1098,7 +1118,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.HTTP = httpConfig if !forNode || httpConfig.IsOn {
config.HTTP = httpConfig
}
} }
// HTTPS // HTTPS
@@ -1109,18 +1131,20 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
return nil, err return nil, err
} }
// SSL if !forNode || httpsConfig.IsOn {
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 && !ignoreCerts { // SSL
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, httpsConfig.SSLPolicyRef.SSLPolicyId, false, cacheMap) if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 && !ignoreCerts {
if err != nil { sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, httpsConfig.SSLPolicyRef.SSLPolicyId, false, dataMap, cacheMap)
return nil, err if err != nil {
return nil, err
}
if sslPolicyConfig != nil {
httpsConfig.SSLPolicy = sslPolicyConfig
}
} }
if sslPolicyConfig != nil {
httpsConfig.SSLPolicy = sslPolicyConfig
}
}
config.HTTPS = httpsConfig config.HTTPS = httpsConfig
}
} }
// TCP // TCP
@@ -1130,7 +1154,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.TCP = tcpConfig if !forNode || tcpConfig.IsOn {
config.TCP = tcpConfig
}
} }
// TLS // TLS
@@ -1141,18 +1167,20 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
return nil, err return nil, err
} }
// SSL if !forNode || tlsConfig.IsOn {
if tlsConfig.SSLPolicyRef != nil && !ignoreCerts { // SSL
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, tlsConfig.SSLPolicyRef.SSLPolicyId, false, cacheMap) if tlsConfig.SSLPolicyRef != nil && !ignoreCerts {
if err != nil { sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, tlsConfig.SSLPolicyRef.SSLPolicyId, false, dataMap, cacheMap)
return nil, err if err != nil {
return nil, err
}
if sslPolicyConfig != nil {
tlsConfig.SSLPolicy = sslPolicyConfig
}
} }
if sslPolicyConfig != nil {
tlsConfig.SSLPolicy = sslPolicyConfig
}
}
config.TLS = tlsConfig config.TLS = tlsConfig
}
} }
// Unix // Unix
@@ -1162,7 +1190,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Unix = unixConfig if !forNode || unixConfig.IsOn {
config.Unix = unixConfig
}
} }
// UDP // UDP
@@ -1172,13 +1202,15 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.UDP = udpConfig if !forNode || udpConfig.IsOn {
config.UDP = udpConfig
}
} }
// Web // Web
if !forList { if !forList {
if server.WebId > 0 { if server.WebId > 0 {
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(server.WebId), cacheMap) webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(server.WebId), false, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1196,14 +1228,18 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.ReverseProxyRef = reverseProxyRef if !forNode || reverseProxyRef.IsOn {
config.ReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if reverseProxyConfig != nil { if reverseProxyConfig != nil {
config.ReverseProxy = reverseProxyConfig if !forNode || reverseProxyConfig.IsOn {
config.ReverseProxy = reverseProxyConfig
}
}
} }
} }
} }
@@ -1427,7 +1463,7 @@ func (this *ServerDAO) CountEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64)
Count() Count()
} }
// FindAllEnabledServersWithWebIds 查找使用某个缓存策略的所有服务 // FindAllEnabledServersWithWebIds 通过WebId查找服务
func (this *ServerDAO) FindAllEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64) (result []*Server, err error) { func (this *ServerDAO) FindAllEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64) (result []*Server, err error) {
if len(webIds) == 0 { if len(webIds) == 0 {
return return
@@ -1435,6 +1471,7 @@ func (this *ServerDAO) FindAllEnabledServersWithWebIds(tx *dbs.Tx, webIds []int6
_, err = this.Query(tx). _, err = this.Query(tx).
State(ServerStateEnabled). State(ServerStateEnabled).
Attr("webId", webIds). Attr("webId", webIds).
UseIndex("webId").
Reuse(false). Reuse(false).
AscPk(). AscPk().
Slice(&result). Slice(&result).
@@ -1557,12 +1594,16 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
} }
// FindEnabledServerWithDomain 根据域名查找服务集群ID // FindEnabledServerWithDomain 根据域名查找服务集群ID
func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (server *Server, err error) { func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, userId int64, domain string) (server *Server, err error) {
if len(domain) == 0 { if len(domain) == 0 {
return return
} }
one, err := this.Query(tx). var query = this.Query(tx)
if userId > 0 {
query.Attr("userId", userId)
}
one, err := query.
State(ServerStateEnabled). State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)"). Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(domain)). Param("domain", strconv.Quote(domain)).
@@ -1581,7 +1622,11 @@ func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (s
var dotIndex = strings.Index(domain, ".") var dotIndex = strings.Index(domain, ".")
if dotIndex > 0 { if dotIndex > 0 {
var wildcardDomain = "*." + domain[dotIndex+1:] var wildcardDomain = "*." + domain[dotIndex+1:]
one, err = this.Query(tx). var wildcardQuery = this.Query(tx)
if userId > 0 {
wildcardQuery.Attr("userId", userId)
}
one, err = wildcardQuery.
State(ServerStateEnabled). State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)"). Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(wildcardDomain)). Param("domain", strconv.Quote(wildcardDomain)).
@@ -2763,6 +2808,28 @@ func (this *ServerDAO) UpdateServerUserId(tx *dbs.Tx, serverId int64, userId int
return this.NotifyUpdate(tx, serverId) return this.NotifyUpdate(tx, serverId)
} }
// UpdateServerName 修改服务名
func (this *ServerDAO) UpdateServerName(tx *dbs.Tx, serverId int64, name string) error {
return this.Query(tx).
Pk(serverId).
Set("name", name).
UpdateQuickly()
}
// FindEnabledServersWithIds 根据ID查找一组服务
func (this *ServerDAO) FindEnabledServersWithIds(tx *dbs.Tx, serverIds []int64) (result []*Server, err error) {
if len(serverIds) == 0 {
return
}
_, err = this.Query(tx).
Pk(serverIds).
Reuse(false).
State(ServerStateEnabled).
Slice(&result).
FindAll()
return
}
// NotifyUpdate 同步服务所在的集群 // NotifyUpdate 同步服务所在的集群
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error { func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
// 创建任务 // 创建任务

View File

@@ -0,0 +1,35 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/dbs"
)
// CopyServerConfigToServers 拷贝服务配置到一组服务
func (this *ServerDAO) CopyServerConfigToServers(tx *dbs.Tx, fromServerId int64, toServerIds []int64, configCode serverconfigs.ConfigCode) error {
return errors.New("not implemented")
}
// CopyServerConfigToGroups 拷贝服务配置到分组
func (this *ServerDAO) CopyServerConfigToGroups(tx *dbs.Tx, fromServerId int64, groupIds []int64, configCode string) error {
return errors.New("not implemented")
}
// CopyServerConfigToCluster 拷贝服务配置到集群
func (this *ServerDAO) CopyServerConfigToCluster(tx *dbs.Tx, fromServerId int64, clusterId int64, configCode string) error {
return errors.New("not implemented")
}
// CopyServerConfigToUser 拷贝服务配置到用户
func (this *ServerDAO) CopyServerConfigToUser(tx *dbs.Tx, fromServerId int64, userId int64, configCode string) error {
return errors.New("not implemented")
}
// CopyServerUAMConfigs 复制UAM设置
func (this *ServerDAO) CopyServerUAMConfigs(tx *dbs.Tx, fromServerId int64, toServerIds []int64) error {
return errors.New("not implemented")
}

View File

@@ -190,7 +190,7 @@ func TestServerDAO_FindAllEnabledServersWithNode_Cache(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
for _, server := range servers { for _, server := range servers {
_, _ = models.SharedServerDAO.ComposeServerConfig(nil, server, false, cacheMap, true, false) _, _ = models.SharedServerDAO.ComposeServerConfig(nil, server, false, nil, cacheMap, true, false)
} }
} }
@@ -201,7 +201,7 @@ func TestServerDAO_FindAllEnabledServersWithNode_Cache(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
for _, server := range servers { for _, server := range servers {
_, _ = models.SharedServerDAO.ComposeServerConfig(nil, server, false, cacheMap, true, false) _, _ = models.SharedServerDAO.ComposeServerConfig(nil, server, false, nil, cacheMap, true, false)
} }
} }
t.Log(time.Since(before).Seconds()*1000, "ms") t.Log(time.Since(before).Seconds()*1000, "ms")
@@ -332,6 +332,16 @@ func TestServerDAO_UpdateServerBandwidth(t *testing.T) {
} }
} }
func TestServerDAO_FindEnabledServersWithIds(t *testing.T) {
var dao = models.NewServerDAO()
var tx *dbs.Tx
servers, err := dao.FindEnabledServersWithIds(tx, []int64{23, 1071})
if err != nil {
t.Fatal(err)
}
t.Log(len(servers), "servers")
}
func BenchmarkServerDAO_CountAllEnabledServers(b *testing.B) { func BenchmarkServerDAO_CountAllEnabledServers(b *testing.B) {
models.SharedServerDAO = models.NewServerDAO() models.SharedServerDAO = models.NewServerDAO()

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -279,7 +280,7 @@ func (this *ServerGroupDAO) InitGroupWeb(tx *dbs.Tx, groupId int64) (int64, erro
} }
// ComposeGroupConfig 组合配置 // ComposeGroupConfig 组合配置
func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forList bool, cacheMap *utils.CacheMap) (*serverconfigs.ServerGroupConfig, error) { func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forNode bool, forList bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.ServerGroupConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -324,7 +325,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
} }
config.HTTPReverseProxyRef = reverseProxyRef config.HTTPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -341,7 +342,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
} }
config.TCPReverseProxyRef = reverseProxyRef config.TCPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -358,7 +359,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
} }
config.UDPReverseProxyRef = reverseProxyRef config.UDPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -369,7 +370,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
// web // web
if group.WebId > 0 { if group.WebId > 0 {
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(group.WebId), cacheMap) webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(group.WebId), true, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -423,6 +424,18 @@ func (this *ServerGroupDAO) ExistsGroup(tx *dbs.Tx, groupId int64) (bool, error)
Exist() Exist()
} }
// FindGroupUserId 读取分组所属用户
func (this *ServerGroupDAO) FindGroupUserId(tx *dbs.Tx, groupId int64) (userId int64, err error) {
if groupId <= 0 {
return
}
return this.Query(tx).
Pk(groupId).
State(ServerGroupStateEnabled).
Result("userId").
FindInt64Col(0)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error { func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId) serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId)

View File

@@ -78,7 +78,7 @@ func (this *Server) DecodeHTTPSPorts() (ports []int) {
if err != nil { if err != nil {
return nil return nil
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil return nil
} }
@@ -120,7 +120,7 @@ func (this *Server) DecodeTLSPorts() (ports []int) {
if err != nil { if err != nil {
return nil return nil
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil return nil
} }

View File

@@ -6,12 +6,15 @@ import (
"errors" "errors"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils" dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"strings"
"time" "time"
) )
@@ -201,7 +204,7 @@ func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx,
// ComposeCertConfig 组合配置 // ComposeCertConfig 组合配置
// ignoreData 是否忽略证书数据,避免因为数据过大影响传输 // ignoreData 是否忽略证书数据,避免因为数据过大影响传输
func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData bool, cacheMap *utils.CacheMap) (*sslconfigs.SSLCertConfig, error) { func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*sslconfigs.SSLCertConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -227,8 +230,17 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
config.Name = cert.Name config.Name = cert.Name
config.Description = cert.Description config.Description = cert.Description
if !ignoreData { if !ignoreData {
config.CertData = cert.CertData if dataMap != nil {
config.KeyData = cert.KeyData if len(cert.CertData) > 0 {
config.CertData = dataMap.Put(cert.CertData)
}
if len(cert.KeyData) > 0 {
config.KeyData = dataMap.Put(cert.KeyData)
}
} else {
config.CertData = cert.CertData
config.KeyData = cert.KeyData
}
} }
config.ServerName = cert.ServerName config.ServerName = cert.ServerName
config.TimeBeginAt = int64(cert.TimeBeginAt) config.TimeBeginAt = int64(cert.TimeBeginAt)
@@ -236,7 +248,13 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
// OCSP // OCSP
if int64(cert.OcspExpiresAt) > time.Now().Unix() { if int64(cert.OcspExpiresAt) > time.Now().Unix() {
config.OCSP = cert.Ocsp if dataMap != nil {
if len(cert.Ocsp) > 0 {
config.OCSP = dataMap.Put(cert.Ocsp)
}
} else {
config.OCSP = cert.Ocsp
}
config.OCSPExpiresAt = int64(cert.OcspExpiresAt) config.OCSPExpiresAt = int64(cert.OcspExpiresAt)
} }
config.OCSPError = cert.OcspError config.OCSPError = cert.OcspError
@@ -267,8 +285,8 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
} }
// CountCerts 计算符合条件的证书数量 // CountCerts 计算符合条件的证书数量
func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64) (int64, error) { func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string) (int64, error) {
query := this.Query(tx). var query = this.Query(tx).
State(SSLCertStateEnabled) State(SSLCertStateEnabled)
if isCA { if isCA {
query.Attr("isCA", true) query.Attr("isCA", true)
@@ -293,12 +311,19 @@ func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isEx
// 只查询管理员上传的 // 只查询管理员上传的
query.Attr("userId", 0) query.Attr("userId", 0)
} }
// 域名
err := this.buildDomainSearchingQuery(query, domains)
if err != nil {
return 0, err
}
return query.Count() return query.Count()
} }
// ListCertIds 列出符合条件的证书 // ListCertIds 列出符合条件的证书
func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, 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, offset int64, size int64) (certIds []int64, err error) {
query := this.Query(tx). var query = this.Query(tx).
State(SSLCertStateEnabled) State(SSLCertStateEnabled)
if isCA { if isCA {
query.Attr("isCA", true) query.Attr("isCA", true)
@@ -324,6 +349,12 @@ func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isE
query.Attr("userId", 0) query.Attr("userId", 0)
} }
// 域名
err = this.buildDomainSearchingQuery(query, domains)
if err != nil {
return nil, err
}
ones, err := query. ones, err := query.
ResultPk(). ResultPk().
DescPk(). DescPk().
@@ -334,7 +365,7 @@ func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isE
return nil, err return nil, err
} }
result := []int64{} var result = []int64{}
for _, one := range ones { for _, one := range ones {
result = append(result, int64(one.(*SSLCert).Id)) result = append(result, int64(one.(*SSLCert).Id))
} }
@@ -364,6 +395,7 @@ func (this *SSLCertDAO) FindAllExpiringCerts(tx *dbs.Tx, days int) (result []*SS
var deltaSeconds = int64(days * 86400) var deltaSeconds = int64(days * 86400)
_, err = this.Query(tx). _, err = this.Query(tx).
State(SSLCertStateEnabled). State(SSLCertStateEnabled).
Attr("isOn", true).
Where("FROM_UNIXTIME(timeEndAt, '%Y-%m-%d')=:day AND FROM_UNIXTIME(notifiedAt, '%Y-%m-%d')!=:today"). Where("FROM_UNIXTIME(timeEndAt, '%Y-%m-%d')=:day AND FROM_UNIXTIME(notifiedAt, '%Y-%m-%d')!=:today").
Param("day", timeutil.FormatTime("Y-m-d", time.Now().Unix()+deltaSeconds)). Param("day", timeutil.FormatTime("Y-m-d", time.Now().Unix()+deltaSeconds)).
Param("today", timeutil.Format("Y-m-d")). Param("today", timeutil.Format("Y-m-d")).
@@ -633,3 +665,73 @@ func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
return nil return nil
} }
// 构造通过域名搜索证书的查询对象
func (this *SSLCertDAO) buildDomainSearchingQuery(query *dbs.Query, domains []string) error {
if len(domains) == 0 {
return nil
}
// 不要查询太多
const maxDomains = 10_000
if len(domains) > maxDomains {
domains = domains[:maxDomains]
}
// 加入通配符
var searchingDomains = []string{}
var domainMap = map[string]bool{}
for _, domain := range domains {
domainMap[domain] = true
}
var reg = regexp.MustCompile(`^[\w*.-]+$`) // 为了下面的SQL语句安全先不支持其他字符
for domain := range domainMap {
if !reg.MatchString(domain) {
continue
}
searchingDomains = append(searchingDomains, domain)
if strings.Count(domain, ".") >= 2 && !strings.HasPrefix(domain, "*.") {
var wildcardDomain = "*" + domain[strings.Index(domain, "."):]
if !domainMap[wildcardDomain] {
domainMap[wildcardDomain] = true
searchingDomains = append(searchingDomains, wildcardDomain)
}
}
}
// 检测 JSON_OVERLAPS() 函数是否可用
var canJSONOverlaps = false
_, funcErr := this.Instance.FindCol(0, "SELECT JSON_OVERLAPS('[1]', '[1]')")
canJSONOverlaps = funcErr == nil
if canJSONOverlaps {
domainsJSON, err := json.Marshal(searchingDomains)
if err != nil {
return err
}
query.
Where("JSON_OVERLAPS(dnsNames, JSON_UNQUOTE(:domainsJSON))").
Param("domainsJSON", string(domainsJSON))
return nil
}
// 不支持JSON_OVERLAPS()的情形
query.Reuse(false)
// TODO 需要判断是否超出max_allowed_packet
var sqlPieces = []string{}
for _, domain := range searchingDomains {
domainJSON, err := json.Marshal(domain)
if err != nil {
return err
}
sqlPieces = append(sqlPieces, "JSON_CONTAINS(dnsNames, '"+string(domainJSON)+"')")
}
if len(sqlPieces) > 0 {
query.Where("(" + strings.Join(sqlPieces, " OR ") + ")")
}
return nil
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
@@ -77,7 +78,7 @@ func (this *SSLPolicyDAO) FindEnabledSSLPolicy(tx *dbs.Tx, id int64) (*SSLPolicy
} }
// ComposePolicyConfig 组合配置 // ComposePolicyConfig 组合配置
func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignoreData bool, cacheMap *utils.CacheMap) (*sslconfigs.SSLPolicy, error) { func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignoreData bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*sslconfigs.SSLPolicy, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -111,7 +112,7 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignore
} }
if len(refs) > 0 { if len(refs) > 0 {
for _, ref := range refs { for _, ref := range refs {
certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, ignoreData, cacheMap) certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, ignoreData, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -133,7 +134,7 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignore
} }
if len(refs) > 0 { if len(refs) > 0 {
for _, ref := range refs { for _, ref := range refs {
certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, ignoreData, cacheMap) certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, ignoreData, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -114,6 +114,20 @@ func (this *NodeClusterTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, clusterId
return result, nil return result, nil
} }
// SumDailyStat 计算当月总流量
func (this *NodeClusterTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, clusterId int64, dayFrom string, dayTo string) (*NodeClusterTrafficDailyStat, error) {
one, err := this.Query(tx).
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes").
Attr("clusterId", clusterId).
Between("day", dayFrom, dayTo).
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*NodeClusterTrafficDailyStat), nil
}
// Clean 清理历史数据 // Clean 清理历史数据
func (this *NodeClusterTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeClusterTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))

View File

@@ -1 +0,0 @@
package stats

View File

@@ -51,7 +51,7 @@ func (this *SysEventDAO) CreateEvent(tx *dbs.Tx, event EventInterface) error {
// 查找事件 // 查找事件
func (this *SysEventDAO) FindEvents(tx *dbs.Tx, size int64) (result []*SysEvent, err error) { func (this *SysEventDAO) FindEvents(tx *dbs.Tx, size int64) (result []*SysEvent, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
Asc(). AscPk().
Limit(size). Limit(size).
Slice(&result). Slice(&result).
FindAll() FindAll()

View File

@@ -0,0 +1,108 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"time"
)
type UpdatingServerListDAO dbs.DAO
func init() {
dbs.OnReadyDone(func() {
var ticker = time.NewTicker(24 * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedUpdatingServerListDAO.CleanExpiredLists(nil, 7)
if err != nil {
remotelogs.Error("UpdatingServerListDAO", "CleanExpiredLists(): "+err.Error())
}
}
})
})
}
func NewUpdatingServerListDAO() *UpdatingServerListDAO {
return dbs.NewDAO(&UpdatingServerListDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUpdatingServerLists",
Model: new(UpdatingServerList),
PkName: "id",
},
}).(*UpdatingServerListDAO)
}
var SharedUpdatingServerListDAO *UpdatingServerListDAO
func init() {
dbs.OnReady(func() {
SharedUpdatingServerListDAO = NewUpdatingServerListDAO()
})
}
// CreateList 创建待更新的服务列表
func (this *UpdatingServerListDAO) CreateList(tx *dbs.Tx, clusterId int64, serverIds []int64) error {
if clusterId <= 0 || len(serverIds) == 0 {
return nil
}
sort.Slice(serverIds, func(i, j int) bool {
return serverIds[i] < serverIds[j]
})
serverIdsJSON, err := json.Marshal(serverIds)
if err != nil {
return err
}
var uniqueId = stringutil.Md5(types.String(clusterId) + "@" + string(serverIdsJSON))
_, _, err = this.Query(tx).
Set("uniqueId", uniqueId).
Set("serverIds", serverIdsJSON).
Set("clusterId", clusterId).
Set("day", timeutil.Format("Ymd")).
Replace() // 使用Replace让ID可以自增
return err
}
// FindLists 查找待更新服务列表
func (this *UpdatingServerListDAO) FindLists(tx *dbs.Tx, clusterIds []int64, lastId int64) (result []*UpdatingServerList, err error) {
if len(clusterIds) == 0 {
return
}
_, err = this.Query(tx).
Attr("clusterId", clusterIds). // 即使clusterIds数量是变化的这里也不需要使用Reuse(false)因为clusterIds通常数量有限
Gt("id", lastId).
AscPk(). // 非常重要
Slice(&result).
FindAll()
return
}
// FindLatestId 读取最新的ID
// 不需要区分集群
func (this *UpdatingServerListDAO) FindLatestId(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
ResultPk().
DescPk().
FindInt64Col(0)
}
// CleanExpiredLists 清除过期列表
func (this *UpdatingServerListDAO) CleanExpiredLists(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 7
}
return this.Query(tx).
Lt("day", timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))).
DeleteQuickly()
}

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,24 @@
package models
import "github.com/iwind/TeaGo/dbs"
// UpdatingServerList 待更新服务列表
type UpdatingServerList struct {
Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
UniqueId string `field:"uniqueId"` // 唯一ID
ServerIds dbs.JSON `field:"serverIds"` // 服务IDs
Day string `field:"day"` // 创建日期
}
type UpdatingServerListOperator struct {
Id any // ID
ClusterId any // 集群ID
UniqueId any // 唯一ID
ServerIds any // 服务IDs
Day any // 创建日期
}
func NewUpdatingServerListOperator() *UpdatingServerListOperator {
return &UpdatingServerListOperator{}
}

View File

@@ -0,0 +1,20 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
)
func (this *UpdatingServerList) DecodeServerIds() []int64 {
if len(this.ServerIds) == 0 {
return nil
}
var serverIds = []int64{}
err := json.Unmarshal(this.ServerIds, &serverIds)
if err != nil {
remotelogs.Error("UpdatingServerList", "DecodeServerIds(): "+err.Error())
}
return serverIds
}

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -26,6 +27,9 @@ const (
UserBandwidthStatTablePartials = 20 UserBandwidthStatTablePartials = 20
) )
var fullDataMap = map[string]bool{} // month => bool
var fullDataLocker = &sync.Mutex{}
func init() { func init() {
dbs.OnReadyDone(func() { dbs.OnReadyDone(func() {
// 清理数据任务 // 清理数据任务
@@ -61,7 +65,7 @@ func init() {
} }
// UpdateUserBandwidth 写入数据 // UpdateUserBandwidth 写入数据
func (this *UserBandwidthStatDAO) UpdateUserBandwidth(tx *dbs.Tx, userId int64, regionId int64, day string, timeAt string, bytes int64, totalBytes int64) error { func (this *UserBandwidthStatDAO) UpdateUserBandwidth(tx *dbs.Tx, userId int64, regionId int64, day string, timeAt string, bytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
if userId <= 0 { if userId <= 0 {
// 如果用户ID不大于0则说明服务不属于任何用户此时不需要处理 // 如果用户ID不大于0则说明服务不属于任何用户此时不需要处理
return nil return nil
@@ -71,18 +75,33 @@ func (this *UserBandwidthStatDAO) UpdateUserBandwidth(tx *dbs.Tx, userId int64,
Table(this.partialTable(userId)). Table(this.partialTable(userId)).
Param("bytes", bytes). Param("bytes", bytes).
Param("totalBytes", totalBytes). Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"userId": userId, "userId": userId,
"regionId": regionId, "regionId": regionId,
"day": day, "day": day,
"timeAt": timeAt, "timeAt": timeAt,
"bytes": bytes, "bytes": bytes,
"totalBytes": totalBytes, "totalBytes": totalBytes,
"avgBytes": totalBytes / 300, "avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
"attackBytes": attackBytes,
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
}, maps.Map{ }, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"), "bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题 "avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+: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"),
}) })
} }
@@ -320,6 +339,127 @@ func (this *UserBandwidthStatDAO) FindDistinctUserIds(tx *dbs.Tx, dayFrom string
return return
} }
// SumUserMonthly 获取某月流量总和
// month 格式为YYYYMM
func (this *UserBandwidthStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, month string) (int64, error) {
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, userId, month)
if err != nil {
return 0, err
}
if !hasFullData {
return SharedServerDailyStatDAO.compatSumUserMonthly(tx, userId, month)
}
return this.Query(tx).
Table(this.partialTable(userId)).
Between("day", month+"01", month+"31").
Attr("userId", userId).
SumInt64("totalBytes", 0)
}
// SumUserDaily 获取某天流量总和
// day 格式为YYYYMMDD
func (this *UserBandwidthStatDAO) SumUserDaily(tx *dbs.Tx, userId int64, regionId int64, day string) (stat *UserBandwidthStat, err error) {
if !regexputils.YYYYMMDD.MatchString(day) {
return nil, nil
}
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, userId, day[:6])
if err != nil {
return nil, err
}
if !hasFullData {
serverStat, err := SharedServerDailyStatDAO.compatSumUserDaily(tx, userId, regionId, day)
if err != nil || serverStat == nil {
return nil, err
}
return serverStat.AsUserBandwidthStat(), nil
}
var query = this.Query(tx)
if regionId > 0 {
query.Attr("regionId", regionId)
}
one, err := query.
Table(this.partialTable(userId)).
Attr("day", day).
Attr("userId", userId).
Result("SUM(totalBytes) AS totalBytes", "SUM(cachedBytes) AS cachedBytes", "SUM(attackBytes) AS attackBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*UserBandwidthStat), nil
}
// SumDailyStat 获取某天内的流量
// dayFrom 格式为YYYYMMDD
// dayTo 格式为YYYYMMDD
func (this *UserBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, userId int64, regionId int64, dayFrom string, dayTo string) (stat *pb.ServerDailyStat, err error) {
if !regexputils.YYYYMMDD.MatchString(dayFrom) {
return nil, errors.New("invalid dayFrom '" + dayFrom + "'")
}
if !regexputils.YYYYMMDD.MatchString(dayTo) {
return nil, errors.New("invalid dayTo '" + dayTo + "'")
}
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, userId, dayFrom[:6])
if err != nil {
return nil, err
}
if !hasFullData {
return SharedServerDailyStatDAO.compatSumDailyStat(tx, userId, 0, regionId, dayFrom, dayTo)
}
stat = &pb.ServerDailyStat{}
if userId <= 0 {
return
}
if dayFrom > dayTo {
dayFrom, dayTo = dayTo, dayFrom
}
var query = this.Query(tx).
Table(this.partialTable(userId)).
Result("SUM(totalBytes) AS totalBytes, SUM(cachedBytes) AS cachedBytes, SUM(countRequests) AS countRequests, SUM(countCachedRequests) AS countCachedRequests, SUM(countAttackRequests) AS countAttackRequests, SUM(attackBytes) AS attackBytes")
query.Attr("userId", userId)
if regionId > 0 {
query.Attr("regionId", regionId)
}
if dayFrom == dayTo {
query.Attr("day", dayFrom)
} else {
query.Between("day", dayFrom, dayTo)
}
one, _, err := query.FindOne()
if err != nil {
return nil, err
}
if one == nil {
return
}
stat.Bytes = one.GetInt64("totalBytes")
stat.CachedBytes = one.GetInt64("cachedBytes")
stat.CountRequests = one.GetInt64("countRequests")
stat.CountCachedRequests = one.GetInt64("countCachedRequests")
stat.CountAttackRequests = one.GetInt64("countAttackRequests")
stat.AttackBytes = one.GetInt64("attackBytes")
return
}
// Clean 清理过期数据 // Clean 清理过期数据
func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error { func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据 var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据
@@ -375,3 +515,48 @@ func (this *UserBandwidthStatDAO) fixUserStat(stat *UserBandwidthStat, useAvg bo
} }
return stat return stat
} }
// HasFullData 检查一个月是否完整数据
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
func (this *UserBandwidthStatDAO) HasFullData(tx *dbs.Tx, userId int64, month string) (bool, error) {
if !regexputils.YYYYMM.MatchString(month) {
return false, errors.New("invalid month '" + month + "'")
}
fullDataLocker.Lock()
hasData, ok := fullDataMap[month]
fullDataLocker.Unlock()
if ok {
return hasData, nil
}
var year = types.Int(month[:4])
var monthInt = types.Int(month[4:])
if year < 2000 || monthInt > 12 || monthInt < 1 {
return false, nil
}
var lastMonth = monthInt - 1
if lastMonth == 0 {
lastMonth = 12
year--
}
var lastMonthString = fmt.Sprintf("%d%02d", year, lastMonth)
one, err := this.Query(tx).
Table(this.partialTable(userId)).
Between("day", lastMonthString+"01", lastMonthString+"31").
DescPk().
Find()
if err != nil {
return false, err
}
var b = one != nil && one.(*UserBandwidthStat).CountRequests > 0
fullDataLocker.Lock()
fullDataMap[month] = b
fullDataLocker.Unlock()
return b, nil
}

View File

@@ -50,7 +50,7 @@ func TestUserBandwidthStatDAO_FindUserPeekBandwidthInDay(t *testing.T) {
func TestUserBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) { func TestUserBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewUserBandwidthStatDAO() var dao = models.NewUserBandwidthStatDAO()
var tx *dbs.Tx var tx *dbs.Tx
err := dao.UpdateUserBandwidth(tx, 1, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300) err := dao.UpdateUserBandwidth(tx, 1, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -93,3 +93,13 @@ func TestUserBandwidthStatDAO_FindPercentileBetweenDays(t *testing.T) {
} }
logs.PrintAsJSON(stat, t) logs.PrintAsJSON(stat, t)
} }
func TestUserBandwidthStatDAO_HasFullData(t *testing.T) {
var tx *dbs.Tx
var dao = models.NewUserBandwidthStatDAO()
var month = "202304"
for i := 0; i < 3; i++ {
t.Log(dao.HasFullData(tx, 1, month))
}
}

View File

@@ -2,25 +2,35 @@ package models
// UserBandwidthStat 用户月带宽峰值 // UserBandwidthStat 用户月带宽峰值
type UserBandwidthStat struct { type UserBandwidthStat struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID UserId uint64 `field:"userId"` // 用户ID
RegionId uint32 `field:"regionId"` // 区域ID RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHII TimeAt string `field:"timeAt"` // 时间点HHII
Bytes uint64 `field:"bytes"` // 带宽 Bytes uint64 `field:"bytes"` // 带宽
TotalBytes uint64 `field:"totalBytes"` // 总流量 TotalBytes uint64 `field:"totalBytes"` // 总流量
AvgBytes uint64 `field:"avgBytes"` // 平均流量 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 UserBandwidthStatOperator struct { type UserBandwidthStatOperator struct {
Id any // ID Id any // ID
UserId any // 用户ID UserId any // 用户ID
RegionId any // 区域ID RegionId any // 区域ID
Day any // 日期YYYYMMDD Day any // 日期YYYYMMDD
TimeAt any // 时间点HHII TimeAt any // 时间点HHII
Bytes any // 带宽 Bytes any // 带宽
TotalBytes any // 总流量 TotalBytes any // 总流量
AvgBytes any // 平均流量 AvgBytes any // 平均流量
CachedBytes any // 缓存的流量
AttackBytes any // 攻击流量
CountRequests any // 请求数
CountCachedRequests any // 缓存的请求数
CountAttackRequests any // 攻击请求数
} }
func NewUserBandwidthStatOperator() *UserBandwidthStatOperator { func NewUserBandwidthStatOperator() *UserBandwidthStatOperator {

View File

@@ -36,7 +36,7 @@ func (this *UserNode) DecodeHTTPS(cacheMap *utils.CacheMap) (*serverconfigs.HTTP
return nil, err return nil, err
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -44,7 +44,7 @@ func (this *UserNode) DecodeHTTPS(cacheMap *utils.CacheMap) (*serverconfigs.HTTP
if config.SSLPolicyRef != nil { if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 { if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(nil, policyId, false, cacheMap) sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(nil, policyId, false, nil, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -54,7 +54,7 @@ func (this *UserNode) DecodeHTTPS(cacheMap *utils.CacheMap) (*serverconfigs.HTTP
} }
} }
err = config.Init() err = config.Init(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -2,6 +2,7 @@ package dbutils
import ( import (
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
"net" "net"
"strings" "strings"
) )
@@ -93,3 +94,36 @@ func IsLocalAddr(addr string) bool {
} }
return false return false
} }
// MySQLVersion 读取当前MySQL版本
func MySQLVersion() (version string, err error) {
db, err := dbs.Default()
if err != nil {
return "", err
}
result, err := db.FindCol(0, "SELECT VERSION()")
if err != nil {
return "", err
}
version = types.String(result)
var suffixIndex = strings.Index(version, "-")
if suffixIndex > 0 {
version = version[:suffixIndex]
}
return
}
func MySQLVersionFrom8() (bool, error) {
version, err := MySQLVersion()
if err != nil {
return false, err
}
if len(version) == 0 {
return false, nil
}
var dotIndex = strings.Index(version, ".")
if dotIndex > 0 {
return types.Int(version[:dotIndex]) >= 8, nil
}
return false, nil
}

View File

@@ -23,3 +23,15 @@ func TestIsLocalAddr(t *testing.T) {
a.IsFalse(dbutils.IsLocalAddr("192.168.2.200")) a.IsFalse(dbutils.IsLocalAddr("192.168.2.200"))
a.IsFalse(dbutils.IsLocalAddr("192.168.2.200:3306")) a.IsFalse(dbutils.IsLocalAddr("192.168.2.200:3306"))
} }
func TestMySQLVersion(t *testing.T) {
version, err := dbutils.MySQLVersion()
if err != nil {
t.Fatal(err)
}
t.Log("version:", version)
}
func TestMySQLVersionFrom8(t *testing.T) {
t.Log(dbutils.MySQLVersionFrom8())
}

View File

@@ -0,0 +1,17 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type CustomLineGroupListResponse struct {
BaseResponse
Data struct {
LineGroups []struct {
Name string `json:"name"`
} `json:"line_groups"`
Info struct {
NowTotal int `json:"now_total"`
Total int `json:"total"`
} `json:"info"`
} `json:"data"`
}

View File

@@ -164,6 +164,53 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
}) })
} }
// 自定义线路分组
var groupsPerPage = 100
var customLineGroupListResponse = new(dnspod.CustomLineGroupListResponse)
err = this.doAPI("/Custom.Line.Group.List", map[string]string{
"domain": domain,
"offset": "0",
"length": types.String(groupsPerPage),
}, customLineGroupListResponse)
if err != nil {
// 忽略自定义分组错误
err = nil
} else {
if len(customLineGroupListResponse.Data.LineGroups) > 0 {
for _, lineGroup := range customLineGroupListResponse.Data.LineGroups {
routes = append(routes, &dnstypes.Route{
Name: "分组:" + lineGroup.Name,
Code: lineGroup.Name,
})
}
}
if customLineGroupListResponse.Data.Info.Total > customLineGroupListResponse.Data.Info.NowTotal {
for page := 1; page <= 100; /** 最多100页 **/ page++ {
err = this.doAPI("/Custom.Line.Group.List", map[string]string{
"domain": domain,
"offset": types.String(page * groupsPerPage),
"length": types.String(groupsPerPage),
}, customLineGroupListResponse)
if err != nil {
// 忽略错误
err = nil
} else {
if len(customLineGroupListResponse.Data.LineGroups) == 0 {
break
}
for _, lineGroup := range customLineGroupListResponse.Data.LineGroups {
routes = append(routes, &dnstypes.Route{
Name: "分组:" + lineGroup.Name,
Code: lineGroup.Name,
})
}
}
}
}
}
return routes, nil return routes, nil
} }

View File

@@ -1,10 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. // Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build !plus //go:build !plus
// +build !plus
package dnsclients package dnsclients
import "github.com/iwind/TeaGo/maps" import (
"github.com/iwind/TeaGo/maps"
)
// FindProvider 查找服务商实例 // FindProvider 查找服务商实例
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface { func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {

View File

@@ -29,8 +29,12 @@ func (this *errorObj) Error() string {
return s return s
} }
// 新错误 // New 新错误
func New(errText string) error { func New(errText string) error {
if !Tea.IsTesting() {
return errors.New(errText)
}
ptr, file, line, ok := runtime.Caller(1) ptr, file, line, ok := runtime.Caller(1)
funcName := "" funcName := ""
if ok { if ok {
@@ -45,7 +49,7 @@ func New(errText string) error {
} }
} }
// 包装已有错误 // Wrap 包装已有错误
func Wrap(err error) error { func Wrap(err error) error {
if err == nil { if err == nil {
return nil return nil

View File

@@ -5,6 +5,7 @@ import (
"github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/files"
stringutil "github.com/iwind/TeaGo/utils/string" stringutil "github.com/iwind/TeaGo/utils/string"
"regexp" "regexp"
"sync"
) )
var SharedDeployManager = NewDeployManager() var SharedDeployManager = NewDeployManager()
@@ -12,9 +13,12 @@ var SharedDeployManager = NewDeployManager()
// DeployManager 节点部署文件管理器 // DeployManager 节点部署文件管理器
// 如果节点部署文件有变化需要重启API节点以便于生效 // 如果节点部署文件有变化需要重启API节点以便于生效
type DeployManager struct { type DeployManager struct {
dir string dir string
nodeFiles []*DeployFile nodeFiles []*DeployFile
nsNodeFiles []*DeployFile nsNodeFiles []*DeployFile
locker sync.Mutex
} }
// NewDeployManager 获取新节点部署文件管理器 // NewDeployManager 获取新节点部署文件管理器
@@ -29,24 +33,27 @@ func NewDeployManager() *DeployManager {
// LoadNodeFiles 加载所有边缘节点文件 // LoadNodeFiles 加载所有边缘节点文件
func (this *DeployManager) LoadNodeFiles() []*DeployFile { func (this *DeployManager) LoadNodeFiles() []*DeployFile {
this.locker.Lock()
defer this.locker.Unlock()
if len(this.nodeFiles) > 0 { if len(this.nodeFiles) > 0 {
return this.nodeFiles return this.nodeFiles
} }
keyMap := map[string]*DeployFile{} // key => File var keyMap = map[string]*DeployFile{} // key => File
reg := regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`) var reg = regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
for _, file := range files.NewFile(this.dir).List() { for _, file := range files.NewFile(this.dir).List() {
name := file.Name() var name = file.Name()
if !reg.MatchString(name) { if !reg.MatchString(name) {
continue continue
} }
matches := reg.FindStringSubmatch(name) var matches = reg.FindStringSubmatch(name)
osName := matches[1] var osName = matches[1]
arch := matches[2] var arch = matches[2]
version := matches[3] var version = matches[3]
key := osName + "_" + arch var key = osName + "_" + arch
oldFile, ok := keyMap[key] oldFile, ok := keyMap[key]
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 { if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
continue continue
@@ -59,7 +66,7 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
} }
} }
result := []*DeployFile{} var result = []*DeployFile{}
for _, v := range keyMap { for _, v := range keyMap {
result = append(result, v) result = append(result, v)
} }
@@ -81,24 +88,27 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
// LoadNSNodeFiles 加载所有NS节点安装文件 // LoadNSNodeFiles 加载所有NS节点安装文件
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile { func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
this.locker.Lock()
defer this.locker.Unlock()
if len(this.nsNodeFiles) > 0 { if len(this.nsNodeFiles) > 0 {
return this.nsNodeFiles return this.nsNodeFiles
} }
keyMap := map[string]*DeployFile{} // key => File var keyMap = map[string]*DeployFile{} // key => File
reg := regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`) var reg = regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
for _, file := range files.NewFile(this.dir).List() { for _, file := range files.NewFile(this.dir).List() {
name := file.Name() var name = file.Name()
if !reg.MatchString(name) { if !reg.MatchString(name) {
continue continue
} }
matches := reg.FindStringSubmatch(name) var matches = reg.FindStringSubmatch(name)
osName := matches[1] var osName = matches[1]
arch := matches[2] var arch = matches[2]
version := matches[3] var version = matches[3]
key := osName + "_" + arch var key = osName + "_" + arch
oldFile, ok := keyMap[key] oldFile, ok := keyMap[key]
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 { if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
continue continue
@@ -111,7 +121,7 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
} }
} }
result := []*DeployFile{} var result = []*DeployFile{}
for _, v := range keyMap { for _, v := range keyMap {
result = append(result, v) result = append(result, v)
} }
@@ -130,3 +140,12 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile {
} }
return nil return nil
} }
// Reload 重置缓存
func (this *DeployManager) Reload() {
this.locker.Lock()
defer this.locker.Unlock()
this.nodeFiles = nil
this.nsNodeFiles = nil
}

View File

@@ -268,8 +268,8 @@ func (this *APINode) InstallSystemService() error {
func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) error { func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) error {
var rpcServer *grpc.Server var rpcServer *grpc.Server
var options = []grpc.ServerOption{ var options = []grpc.ServerOption{
grpc.MaxRecvMsgSize(128 * 1024 * 1024), grpc.MaxRecvMsgSize(512 << 20),
grpc.MaxSendMsgSize(128 * 1024 * 1024), grpc.MaxSendMsgSize(512 << 20),
grpc.UnaryInterceptor(this.unaryInterceptor), grpc.UnaryInterceptor(this.unaryInterceptor),
} }
@@ -306,13 +306,27 @@ func (this *APINode) checkDB() error {
logs.Println("[API_NODE]" + errString) logs.Println("[API_NODE]" + errString)
this.addStartIssue("db", errString, this.dbIssueSuggestion(errString)) this.addStartIssue("db", errString, this.dbIssueSuggestion(errString))
// 决定是否尝试启动本地的MySQL
if strings.Contains(err.Error(), "connection refused") {
config, _ := db.Config()
if config != nil && (strings.Contains(config.Dsn, "tcp(127.0.0.1:") || strings.Contains(config.Dsn, "tcp(localhost:")) && os.Getgid() == 0 /** ROOT 用户 **/ {
var mysqldSafeFile = "/usr/local/mysql/bin/mysqld_safe"
_, err = os.Stat(mysqldSafeFile)
if err == nil {
logs.Println("[API_NODE]try to start local mysql server from '" + mysqldSafeFile + "' ...")
var mysqlCmd = exec.Command(mysqldSafeFile)
_ = mysqlCmd.Start()
}
}
}
// 多次尝试 // 多次尝试
var maxTries = 600 var maxTries = 600
if Tea.IsTesting() { if Tea.IsTesting() {
maxTries = 600 maxTries = 600
} }
for i := 0; i <= maxTries; i++ { for i := 0; i <= maxTries; i++ {
_, err := db.Exec("SELECT 1") _, err = db.Exec("SELECT 1")
if err != nil { if err != nil {
if i == maxTries-1 { if i == maxTries-1 {
return err return err
@@ -741,6 +755,41 @@ func (this *APINode) listenSock() error {
"code": teaconst.InstanceCode, "code": teaconst.InstanceCode,
}, },
}) })
case "lookupToken":
var role = maps.NewMap(cmd.Params).GetString("role")
switch role {
case "admin", "user", "api":
tokens, err := models.SharedApiTokenDAO.FindAllEnabledAPITokens(nil, role)
if err != nil {
_ = cmd.Reply(&gosock.Command{
Params: map[string]any{
"isOk": false,
"err": err.Error(),
},
})
} else {
var tokenMaps = []maps.Map{}
for _, token := range tokens {
tokenMaps = append(tokenMaps, maps.Map{
"nodeId": token.NodeId,
"secret": token.Secret,
})
}
_ = cmd.Reply(&gosock.Command{
Params: map[string]any{
"isOk": true,
"tokens": tokenMaps,
},
})
}
default:
_ = cmd.Reply(&gosock.Command{
Params: map[string]any{
"isOk": false,
"err": "unsupported role '" + role + "'",
},
})
}
} }
}) })

View File

@@ -559,6 +559,12 @@ func (this *APINode) registerServices(server *grpc.Server) {
this.rest(instance) this.rest(instance)
} }
{
var instance = this.serviceInstance(&services.UpdatingServerListService{}).(*services.UpdatingServerListService)
pb.RegisterUpdatingServerListServiceServer(server, instance)
this.rest(instance)
}
APINodeServicesRegister(this, server) APINodeServicesRegister(this, server)
// TODO check service names // TODO check service names

View File

@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package nodes package nodes
@@ -31,7 +32,7 @@ func (this *NodeStatusExecutor) updateMem(status *nodeconfigs.NodeStatus) {
if minFreeMemory > 1<<30 { if minFreeMemory > 1<<30 {
minFreeMemory = 1 << 30 minFreeMemory = 1 << 30
} }
if stat.Free < minFreeMemory { if stat.Available > 0 && stat.Available < minFreeMemory {
runtime.GC() runtime.GC()
debug.FreeOSMemory() debug.FreeOSMemory()
} }

View File

@@ -17,7 +17,7 @@ var sharedDAO DAOInterface
func init() { func init() {
// 定期上传日志 // 定期上传日志
ticker := time.NewTicker(60 * time.Second) var ticker = time.NewTicker(60 * time.Second)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := uploadLogs() err := uploadLogs()

View File

@@ -232,6 +232,12 @@ func (this *ACMETaskService) CreateACMETask(ctx context.Context, req *pb.CreateA
req.AuthType = acme.AuthTypeDNS req.AuthType = acme.AuthTypeDNS
} }
if adminId > 0 {
if req.UserId > 0 {
userId = req.UserId
}
}
var tx = this.NullTx() var tx = this.NullTx()
taskId, err := acmemodels.SharedACMETaskDAO.CreateACMETask(tx, adminId, userId, req.AuthType, req.AcmeUserId, req.DnsProviderId, req.DnsDomain, req.Domains, req.AutoRenew, req.AuthURL) taskId, err := acmemodels.SharedACMETaskDAO.CreateACMETask(tx, adminId, userId, req.AuthType, req.AcmeUserId, req.DnsProviderId, req.DnsDomain, req.Domains, req.AutoRenew, req.AuthURL)
if err != nil { if err != nil {
@@ -414,6 +420,12 @@ func (this *ACMETaskService) FindEnabledACMETask(ctx context.Context, req *pb.Fi
} }
} }
// 证书
var pbCert *pb.SSLCert
if task.CertId > 0 {
pbCert = &pb.SSLCert{Id: int64(task.CertId)}
}
return &pb.FindEnabledACMETaskResponse{AcmeTask: &pb.ACMETask{ return &pb.FindEnabledACMETaskResponse{AcmeTask: &pb.ACMETask{
Id: int64(task.Id), Id: int64(task.Id),
IsOn: task.IsOn, IsOn: task.IsOn,
@@ -425,5 +437,6 @@ func (this *ACMETaskService) FindEnabledACMETask(ctx context.Context, req *pb.Fi
AcmeUser: pbACMEUser, AcmeUser: pbACMEUser,
AuthType: task.AuthType, AuthType: task.AuthType,
AuthURL: task.AuthURL, AuthURL: task.AuthURL,
SslCert: pbCert,
}}, nil }}, nil
} }

View File

@@ -22,6 +22,12 @@ func (this *ACMEUserService) CreateACMEUser(ctx context.Context, req *pb.CreateA
var tx = this.NullTx() var tx = this.NullTx()
if adminId > 0 {
if req.UserId > 0 {
userId = req.UserId
}
}
acmeUserId, err := acmemodels.SharedACMEUserDAO.CreateACMEUser(tx, adminId, userId, req.AcmeProviderCode, req.AcmeProviderAccountId, req.Email, req.Description) acmeUserId, err := acmemodels.SharedACMEUserDAO.CreateACMEUser(tx, adminId, userId, req.AcmeProviderCode, req.AcmeProviderAccountId, req.Email, req.Description)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -127,7 +127,7 @@ func (this *AdminService) FindAdminFullname(ctx context.Context, req *pb.FindAdm
// FindEnabledAdmin 获取管理员信息 // FindEnabledAdmin 获取管理员信息
func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnabledAdminRequest) (*pb.FindEnabledAdminResponse, error) { func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnabledAdminRequest) (*pb.FindEnabledAdminResponse, error) {
_, err := this.ValidateAdmin(ctx) adminId, err := this.ValidateAdmin(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -136,6 +136,12 @@ func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnab
var tx = this.NullTx() var tx = this.NullTx()
// 超级管理员才能查看是否为弱密码
isSuperAdmin, err := models.SharedAdminDAO.CheckSuperAdmin(tx, adminId)
if err != nil {
return nil, err
}
admin, err := models.SharedAdminDAO.FindEnabledAdmin(tx, req.AdminId) admin, err := models.SharedAdminDAO.FindEnabledAdmin(tx, req.AdminId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -144,7 +150,7 @@ func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnab
return &pb.FindEnabledAdminResponse{Admin: nil}, nil return &pb.FindEnabledAdminResponse{Admin: nil}, nil
} }
pbModules := []*pb.AdminModule{} var pbModules = []*pb.AdminModule{}
modules := []*systemconfigs.AdminModule{} modules := []*systemconfigs.AdminModule{}
if len(admin.Modules) > 0 { if len(admin.Modules) > 0 {
err = json.Unmarshal(admin.Modules, &modules) err = json.Unmarshal(admin.Modules, &modules)
@@ -178,14 +184,15 @@ func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnab
} }
result := &pb.Admin{ result := &pb.Admin{
Id: int64(admin.Id), Id: int64(admin.Id),
Fullname: admin.Fullname, Fullname: admin.Fullname,
Username: admin.Username, Username: admin.Username,
IsOn: admin.IsOn, IsOn: admin.IsOn,
IsSuper: admin.IsSuper, IsSuper: admin.IsSuper,
Modules: pbModules, Modules: pbModules,
OtpLogin: pbOtpAuth, OtpLogin: pbOtpAuth,
CanLogin: admin.CanLogin, CanLogin: admin.CanLogin,
HasWeakPassword: isSuperAdmin && admin.HasWeakPassword(),
} }
return &pb.FindEnabledAdminResponse{Admin: result}, nil return &pb.FindEnabledAdminResponse{Admin: result}, nil
} }
@@ -347,7 +354,7 @@ func (this *AdminService) UpdateAdmin(ctx context.Context, req *pb.UpdateAdminRe
// CountAllEnabledAdmins 计算管理员数量 // CountAllEnabledAdmins 计算管理员数量
func (this *AdminService) CountAllEnabledAdmins(ctx context.Context, req *pb.CountAllEnabledAdminsRequest) (*pb.RPCCountResponse, error) { func (this *AdminService) CountAllEnabledAdmins(ctx context.Context, req *pb.CountAllEnabledAdminsRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx) adminId, err := this.ValidateAdmin(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -356,7 +363,17 @@ func (this *AdminService) CountAllEnabledAdmins(ctx context.Context, req *pb.Cou
var tx = this.NullTx() var tx = this.NullTx()
count, err := models.SharedAdminDAO.CountAllEnabledAdmins(tx) // 超级管理员才能查看是否为弱密码
isSuperAdmin, err := models.SharedAdminDAO.CheckSuperAdmin(tx, adminId)
if err != nil {
return nil, err
}
if !isSuperAdmin && req.HasWeakPassword {
return this.SuccessCount(0)
}
count, err := models.SharedAdminDAO.CountAllEnabledAdmins(tx, req.Keyword, req.HasWeakPassword)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -365,7 +382,7 @@ func (this *AdminService) CountAllEnabledAdmins(ctx context.Context, req *pb.Cou
// ListEnabledAdmins 列出单页的管理员 // ListEnabledAdmins 列出单页的管理员
func (this *AdminService) ListEnabledAdmins(ctx context.Context, req *pb.ListEnabledAdminsRequest) (*pb.ListEnabledAdminsResponse, error) { func (this *AdminService) ListEnabledAdmins(ctx context.Context, req *pb.ListEnabledAdminsRequest) (*pb.ListEnabledAdminsResponse, error) {
_, err := this.ValidateAdmin(ctx) adminId, err := this.ValidateAdmin(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -374,12 +391,22 @@ func (this *AdminService) ListEnabledAdmins(ctx context.Context, req *pb.ListEna
var tx = this.NullTx() var tx = this.NullTx()
admins, err := models.SharedAdminDAO.ListEnabledAdmins(tx, req.Offset, req.Size) // 超级管理员才能查看是否为弱密码
isSuperAdmin, err := models.SharedAdminDAO.CheckSuperAdmin(tx, adminId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result := []*pb.Admin{} if !isSuperAdmin && req.HasWeakPassword {
return &pb.ListEnabledAdminsResponse{Admins: nil}, nil
}
admins, err := models.SharedAdminDAO.ListEnabledAdmins(tx, req.Keyword, req.HasWeakPassword, req.Offset, req.Size)
if err != nil {
return nil, err
}
var result = []*pb.Admin{}
for _, admin := range admins { for _, admin := range admins {
var pbOtpAuth *pb.Login = nil var pbOtpAuth *pb.Login = nil
{ {
@@ -398,14 +425,15 @@ func (this *AdminService) ListEnabledAdmins(ctx context.Context, req *pb.ListEna
} }
result = append(result, &pb.Admin{ result = append(result, &pb.Admin{
Id: int64(admin.Id), Id: int64(admin.Id),
Fullname: admin.Fullname, Fullname: admin.Fullname,
Username: admin.Username, Username: admin.Username,
IsOn: admin.IsOn, IsOn: admin.IsOn,
IsSuper: admin.IsSuper, IsSuper: admin.IsSuper,
CreatedAt: int64(admin.CreatedAt), CreatedAt: int64(admin.CreatedAt),
OtpLogin: pbOtpAuth, OtpLogin: pbOtpAuth,
CanLogin: admin.CanLogin, CanLogin: admin.CanLogin,
HasWeakPassword: isSuperAdmin && admin.HasWeakPassword(),
}) })
} }

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