Compare commits

..

96 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
149 changed files with 197712 additions and 965 deletions

View File

@@ -12,4 +12,5 @@ dbs:
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"
"log"
"os"
"strings"
)
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() {
nodes.NewAPINode().Start()

View File

@@ -4,12 +4,11 @@ import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"go/format"
"os"
"path/filepath"
"strconv"
)
func main() {
@@ -23,53 +22,20 @@ func main() {
fmt.Println("[ERROR]" + err.Error())
return
}
resultsJSON, err := json.Marshal(results)
prettyResultsJSON, err := json.MarshalIndent(results, "", " ")
if err != nil {
fmt.Println("[ERROR]" + err.Error())
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 {
fmt.Println("[ERROR]can not find sql.go")
return
}
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)
// 写入到 sql.json 中
var dir = filepath.Dir(Tea.Root)
err = os.WriteFile(dir+"/internal/setup/sql.json", prettyResultsJSON, 0666)
if err != nil {
logs.Println("[ERROR]load sql failed: " + err.Error())
}
}
`)
dst, err := format.Source(content)
if err != nil {
fmt.Println("[ERROR]format code failed: " + err.Error())
fmt.Println("[ERROR]" + err.Error())
return
}
err = os.WriteFile(sqlFile, dst, 0666)
if err != nil {
fmt.Println("[ERROR]write file failed: " + err.Error())
return
}
fmt.Println("ok")
}

12
go.mod
View File

@@ -11,7 +11,7 @@ require (
github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1
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/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
@@ -21,8 +21,8 @@ require (
github.com/shirou/gopsutil/v3 v3.22.2
github.com/smartwalle/alipay/v3 v3.1.7
golang.org/x/crypto v0.1.0
golang.org/x/net v0.7.0
golang.org/x/sys v0.5.0
golang.org/x/net v0.8.0
golang.org/x/sys v0.6.0
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -44,9 +44,9 @@ require (
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
google.golang.org/protobuf v1.28.0 // 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/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-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.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/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
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/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-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/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
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.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
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-20180826012351-8a410e7b638d/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
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-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-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-20180909124046-d0be0721c37e/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-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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
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.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.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.5/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-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.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
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-20191011141410-1b5146add898/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
const (
Version = "0.6.4.1"
Version = "1.1.0"
ProductName = "Edge API"
ProcessName = "edge-api"
@@ -18,7 +18,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.6.4"
NodeVersion = "1.1.0"
// SQLVersion SQL版本号
SQLVersion = "11"

View File

@@ -7,13 +7,29 @@ import (
"fmt"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"os"
"strings"
"time"
)
var (
IsPlus = false
Edition = ""
MaxNodes int32 = 0
NodeId int64 = 0
Debug = false
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,
KeyData: keyData,
}
err = sslConfig.Init()
err = sslConfig.Init(nil)
if err != nil {
errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error()
return

View File

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

View File

@@ -1,6 +1,7 @@
package models
import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
@@ -266,17 +267,36 @@ func (this *AdminDAO) FindAllAdminModules(tx *dbs.Tx) (result []*Admin, err erro
}
// CountAllEnabledAdmins 计算所有管理员数量
func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool) (int64, error) {
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).
Count()
}
// ListEnabledAdmins 列出单页的管理员
func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, offset int64, size int64) (result []*Admin, err error) {
_, err = this.Query(tx).
func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool, offset int64, size int64) (result []*Admin, err error) {
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).
Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin").
Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin", "password").
Offset(offset).
Limit(size).
DescPk().
@@ -292,3 +312,15 @@ func (this *AdminDAO) UpdateAdminTheme(tx *dbs.Tx, adminId int64, theme string)
Set("theme", theme).
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
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
}
err = config.Init()
err = config.Init(nil)
if err != nil {
return nil, err
}
@@ -45,7 +45,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
if config.SSLPolicyRef != nil {
var policyId = config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap)
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil {
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 {
return nil, err
}
@@ -129,13 +129,13 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if !IsNotNull(this.RestHTTPS) {
return nil, nil
}
config := &serverconfigs.HTTPSProtocolConfig{}
var config = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(this.RestHTTPS, config)
if err != nil {
return nil, err
}
err = config.Init()
err = config.Init(nil)
if err != nil {
return nil, err
}
@@ -143,7 +143,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap)
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil {
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 {
return nil, err
}

View File

@@ -12,13 +12,16 @@ import (
type DNSTaskType = string
const (
DNSTaskTypeClusterChange DNSTaskType = "clusterChange"
DNSTaskTypeClusterChange DNSTaskType = "clusterChange" // 集群节点、服务发生变化
DNSTaskTypeClusterNodesChange DNSTaskType = "clusterNodesChange" // 集群中节点发生变化
DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
DNSTaskTypeNodeChange DNSTaskType = "nodeChange"
DNSTaskTypeServerChange DNSTaskType = "serverChange"
DNSTaskTypeDomainChange DNSTaskType = "domainChange"
)
var DNSTasksNotifier = make(chan bool, 2)
type DNSTaskDAO dbs.DAO
func NewDNSTaskDAO() *DNSTaskDAO {
@@ -64,7 +67,17 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
"error": "",
"version": time.Now().UnixNano(),
})
return err
if err != nil {
return err
}
// 通知更新
select {
case DNSTasksNotifier <- true:
default:
}
return nil
}
// CreateClusterTask 生成集群变更任务
@@ -156,10 +169,24 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
}
// 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 {
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()
op.Id = taskId
op.IsDone = true

View File

@@ -105,7 +105,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
// 检查节点
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 {
return nil, err
}
@@ -162,17 +162,36 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
return nil, err
}
if len(ipAddr) == 0 {
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,
})
// 检查是否有离线
anyIPAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, false, nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
if len(anyIPAddr) > 0 {
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,
})
} 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
}

View File

@@ -237,7 +237,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
if len(accessLog.TimeISO8601) > 10 {
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
} else {
timeutil.FormatTime("Ymd", accessLog.Timestamp)
day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
}
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)
}
// 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 组合配置
func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPAuthPolicy, error) {
if cacheMap == nil {

View File

@@ -157,6 +157,9 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
return errors.New("invalid policyId")
}
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames)
if err != nil {
return err
@@ -164,7 +167,31 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
var op = NewHTTPHeaderPolicyOperator()
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)
if err != nil {
return err
@@ -220,9 +247,19 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
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
if IsNotNull(policy.Cors) {
var corsConfig = &shared.HTTPCORSHeaderConfig{}
var corsConfig = shared.NewHTTPCORSHeaderConfig()
err = json.Unmarshal(policy.Cors, corsConfig)
if err != nil {
return nil, err

View File

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

View File

@@ -150,7 +150,7 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
}
// 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 {
cacheMap = utils.NewCacheMap()
}
@@ -168,7 +168,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
return nil, nil
}
config := &serverconfigs.HTTPLocationConfig{}
var config = &serverconfigs.HTTPLocationConfig{}
config.Id = int64(location.Id)
config.IsOn = location.IsOn
config.Description = location.Description
@@ -179,7 +179,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
// web
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 {
return nil, err
}
@@ -195,7 +195,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
}
config.ReverseProxyRef = ref
if ref.ReverseProxyId > 0 {
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, cacheMap)
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -292,13 +292,13 @@ func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, web
}
// 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 {
config, err := this.ComposeLocationConfig(tx, ref.LocationId, cacheMap)
config, err := this.ComposeLocationConfig(tx, ref.LocationId, forNode, dataMap, cacheMap)
if err != nil {
return nil, err
}
children, err := this.ConvertLocationRefs(tx, ref.Children, cacheMap)
children, err := this.ConvertLocationRefs(tx, ref.Children, forNode, dataMap, cacheMap)
if err != nil {
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)
}
// 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 组合配置
func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPPageConfig, error) {
if cacheMap == nil {

View File

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

View File

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

View File

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

View File

@@ -51,12 +51,12 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
var dao = models.NewIPItemDAO()
var n = 10
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 {
t.Fatal(err)
}
_ = itemId
/**err = dao.Query(tx).Pk(itemId).Set("state", 0).UpdateQuickly()
/**err = dao.Query(tx).Pk(itemId).Attr("state", 0).UpdateQuickly()
if err != nil {
t.Fatal(err)
}**/

View File

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

View File

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

View File

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

View File

@@ -60,11 +60,11 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
}
// 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)
dayTo = this.formatDay(dayTo)
query := this.Query(tx)
var query = this.Query(tx)
if len(dayFrom) > 0 {
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)").
Param("keyword", dbutils.QuoteLike(keyword))
}
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型
switch userType {
@@ -89,11 +92,11 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
}
// 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)
dayTo = this.formatDay(dayTo)
query := this.Query(tx)
var query = this.Query(tx)
if len(dayFrom) > 0 {
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))
}
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型
switch userType {
case "admin":

View File

@@ -52,7 +52,9 @@ const (
MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃
MessageTypeConnectivity MessageType = "Connectivity"
MessageTypeConnectivity MessageType = "Connectivity" // 连通性
MessageTypeNodeSchedule MessageType = "NodeSchedule" // 节点调度信息
MessageTypeNodeOfflineDay MessageType = "NodeOfflineDay" // 节点到下线日期
)
type MessageDAO dbs.DAO
@@ -155,7 +157,7 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, role string, clusterId int
// CreateMessage 创建普通消息
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)
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域名
type NSDomain struct {
Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号
Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
RecordsHealthCheck dbs.JSON `field:"recordsHealthCheck"` // 记录健康检查设置
CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号
Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
}
type NSDomainOperator struct {
Id any // ID
ClusterId any // 集群ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 域名
GroupIds any // 分组ID
Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间
CreatedAt any // 创建时间
Version any // 版本号
Status any // 状态none|verified
State any // 状态
Id any // ID
ClusterId any // 集群ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 域名
GroupIds any // 分组ID
Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间
RecordsHealthCheck any // 记录健康检查设置
CreatedAt any // 创建时间
Version any // 版本号
Status any // 状态none|verified
State any // 状态
}
func NewNSDomainOperator() *NSDomainOperator {

View File

@@ -20,6 +20,10 @@ type NSRecord struct {
Ttl uint32 `field:"ttl"` // TTL
Weight uint32 `field:"weight"` // 权重
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"` // 创建时间
Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态
@@ -42,6 +46,10 @@ type NSRecordOperator struct {
Ttl any // TTL
Weight any // 权重
RouteIds any // 线路
HealthCheck any // 健康检查配置
CountUp any // 连续上线次数
CountDown any // 连续离线次数
IsUp any // 是否在线
CreatedAt any // 创建时间
Version 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).
Pk(clusterId).
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()
if err != nil || cluster == nil {
return nil, err
@@ -1077,7 +1077,7 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return err
}
return this.NotifyUpdate(tx, clusterId)
return this.NotifyUAMUpdate(tx, clusterId)
}
uamPolicyJSON, err := json.Marshal(uamPolicy)
@@ -1092,10 +1092,10 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
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) {
var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId)
if cacheMap != nil {
@@ -1125,6 +1125,146 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
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设置
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
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)
}
// 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更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {

View File

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

View File

@@ -356,7 +356,7 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
// 关键词
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))
}
@@ -435,6 +435,16 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
valueField = "load1m"
isAsc = false
ifNullValue = -1
case "connectionsAsc":
valueItem = "connections"
valueField = "total"
isAsc = true
ifNullValue = 1000
case "connectionsDesc":
valueItem = "connections"
valueField = "total"
isAsc = false
ifNullValue = -1
default:
query.Desc("level")
}
@@ -830,7 +840,24 @@ func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *node
Set("isActive", true).
Set("status", nodeStatusJSON).
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 获取节点状态
@@ -875,7 +902,10 @@ func (this *NodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstalled
Set("isInstalled", isInstalled).
Set("installStatus", "null"). // 重置安装状态
Update()
return err
if err != nil {
return err
}
return this.NotifyDNSUpdate(tx, nodeId)
}
// FindNodeInstallStatus 查询节点的安装状态
@@ -932,11 +962,16 @@ func (this *NodeDAO) UpdateNodeInstallStatus(tx *dbs.Tx, nodeId int64, status *N
// ComposeNodeConfig 组合配置
// 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 {
cacheMap = utils.NewCacheMap()
}
// 放入到缓存中,以便于后面继续使用
if dataMap != nil {
cacheMap.Put("DataMap", dataMap)
}
node, err := this.FindEnabledNode(tx, nodeId)
if err != nil {
return nil, err
@@ -951,6 +986,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
var config = &nodeconfigs.NodeConfig{
Id: int64(node.Id),
Edition: teaconst.Edition,
NodeId: node.UniqueId,
Secret: node.Secret,
IsOn: node.IsOn,
@@ -963,8 +999,17 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
GroupId: int64(node.GroupId),
EnableIPLists: node.EnableIPLists,
APINodeAddrs: node.DecodeAPINodeAddrs(),
DataMap: dataMap,
}
// 待更新服务ID
updatingServerListId, err := SharedUpdatingServerListDAO.FindLatestId(tx)
if err != nil {
return nil, err
}
config.UpdatingServerListId = updatingServerListId
// API节点IP
apiNodeIPs, err := SharedAPINodeDAO.FindAllEnabledAPIAccessIPs(tx, cacheMap)
if err != nil {
@@ -999,7 +1044,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
}
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 {
return nil, err
}
@@ -1040,6 +1085,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
config.HTTPCCPolicies = map[int64]*nodeconfigs.HTTPCCPolicy{}
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds {
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
}
// 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
if clusterIndex == 0 {
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) {
_, err = this.Query(tx).
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())).
Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)").
Slice(&result).
@@ -1485,7 +1575,7 @@ func (this *NodeDAO) UpdateNodeRegionId(tx *dbs.Tx, nodeId int64, regionId int64
}
// 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 {
return nil, nil
}
@@ -1504,7 +1594,8 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
State(NodeStateEnabled).
Attr("isOn", 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().
Slice(&result).
FindAll()
@@ -1529,7 +1620,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error)
one, err := this.Query(tx).
State(NodeStateEnabled).
Pk(nodeId).
Result("id", "name", "dnsRoutes", "clusterId", "isOn").
Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus").
Find()
if one == nil {
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 {
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
import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
@@ -47,21 +49,40 @@ func TestNodeDAO_FindEnabledNodeClusterIds(t *testing.T) {
func TestNodeDAO_ComposeNodeConfig(t *testing.T) {
dbs.NotifyReady()
before := time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
var before = time.Now()
var tx *dbs.Tx
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 {
t.Fatal(err)
}
nodeConfig.DataMap = dataMap
t.Log(len(nodeConfig.Servers), "servers")
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) {
@@ -71,7 +92,7 @@ func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) {
var tx *dbs.Tx
var cacheMap = utils.NewCacheMap()
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, cacheMap)
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, nil, cacheMap)
if err != nil {
t.Fatal(err)
}

View File

@@ -307,7 +307,7 @@ func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddressId(tx *dbs.Tx, nodeId
FindInt64Col(0)
}
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问的IP地址
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问且在线的IP地址
func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 {
role = nodeconfigs.NodeRoleNode
@@ -326,6 +326,24 @@ func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId
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地址数量
// TODO 目前支持边缘节点将来支持NS节点
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解析器
EnableIPLists bool `field:"enableIPLists"` // 启用IP名单
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 {
@@ -85,6 +91,12 @@ type NodeOperator struct {
DnsResolver any // DNS解析器
EnableIPLists any // 启用IP名单
ApiNodeAddrs any // API节点地址
OfflineDay any // 下线日期YYYYMMDD
OfflineIsNotified any // 下线是否已通知
IsBackupForCluster any // 是否为集群备用节点
IsBackupForGroup any // 是否为分组备用节点
BackupIPs any // 备用IP
ActionStatus any // 当前动作配置
}
func NewNodeOperator() *NodeOperator {

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"time"
)
@@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) {
if len(this.InstallStatus) == 0 {
return NewNodeInstallStatus(), nil
}
status := &NodeInstallStatus{}
var status = &NodeInstallStatus{}
err := json.Unmarshal(this.InstallStatus, status)
if err != nil {
return NewNodeInstallStatus(), err
@@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
if len(this.Status) == 0 {
return nil, nil
}
status := &nodeconfigs.NodeStatus{}
var status = &nodeconfigs.NodeStatus{}
err := json.Unmarshal(this.Status, status)
if err != nil {
return nil, err
@@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
// DNSRouteCodes 所有的DNS线路
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 {
return routes
}
@@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string {
// DNSRouteCodesForDomainId DNS线路
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 {
return nil, nil
}
@@ -80,7 +81,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
// DecodeConnectedAPINodeIds 连接的API
func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
apiNodeIds := []int64{}
var apiNodeIds = []int64{}
if IsNotNull(this.ConnectedAPINodes) {
err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
if err != nil {
@@ -214,3 +215,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
}
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" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
// NS相关
@@ -236,6 +240,7 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
var query = this.Query(tx).
Attr("role", role).
Attr("nodeId", nodeId).
UseIndex("nodeId").
Asc("version")
if version > 0 {
query.Lt("LENGTH(version)", 19) // 兼容以往版本
@@ -294,8 +299,8 @@ func (this *NodeTaskDAO) FindAllDoingNodeTasksWithClusterId(tx *dbs.Tx, role str
Gt("nodeId", 0).
Where("(isDone=0 OR (isDone=1 AND isOk=0))").
Desc("isDone").
Asc().
Asc("nodeId").
AscPk().
Slice(&result).
FindAll()
return

View File

@@ -1,17 +1,19 @@
package models
package models_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"testing"
"time"
)
func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
@@ -22,7 +24,7 @@ func TestNodeTaskDAO_CreateClusterTask(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
@@ -33,9 +35,22 @@ func TestNodeTaskDAO_ExtractClusterTask(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
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 (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
@@ -84,7 +84,9 @@ func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int
if err != nil {
return err
}
return nil
// 触发钩子
return this.increaseDailyStatHook(tx, role, nodeId)
}
// FindDailyStats 获取日期之间统计
@@ -117,6 +119,21 @@ func (this *NodeTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, role string, nod
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 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
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 (
_ "github.com/go-sql-driver/mysql"

View File

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

View File

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

View File

@@ -37,11 +37,15 @@ func init() {
// CreateValue 创建值
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 hour = timeutil.FormatTime("YmdH", createdAt)
var minute = timeutil.FormatTime("YmdHi", createdAt)
return this.Query(tx).
err := this.Query(tx).
InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId,
"role": role,
@@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
}, maps.Map{
"value": valueJSON,
})
if err != nil {
return err
}
// 触发钩子
err = this.nodeValueHook(tx, role, nodeId, item, valueJSON)
if err != nil {
return err
}
return nil
}
// Clean 清除数据
@@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI
// FindLatestNodeValue 获取最近一条数据
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).
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序列号
Email string `field:"email"` // 管理员邮箱
DetectAgents bool `field:"detectAgents"` // 是否监测Agents
CheckingPorts bool `field:"checkingPorts"` // 自动检测端口
}
type NSClusterOperator struct {
@@ -47,6 +48,7 @@ type NSClusterOperator struct {
SoaSerial any // SOA序列号
Email any // 管理员邮箱
DetectAgents any // 是否监测Agents
CheckingPorts any // 自动检测端口
}
func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -275,8 +275,66 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
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 将源站信息转换为配置
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 {
cacheMap = utils.NewCacheMap()
}
@@ -403,7 +461,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
}
config.CertRef = ref
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 {
return nil, err
}

View File

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

View File

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

View File

@@ -81,7 +81,7 @@ func (this *ReverseProxyDAO) FindEnabledReverseProxy(tx *dbs.Tx, id int64) (*Rev
}
// 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 {
cacheMap = utils.NewCacheMap()
}
@@ -125,7 +125,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, err
}
for _, ref := range originRefs {
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, cacheMap)
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -142,7 +142,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, err
}
for _, ref := range originRefs {
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, cacheMap)
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -243,6 +243,115 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
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 修改反向代理调度算法
func (this *ReverseProxyDAO) UpdateReverseProxyScheduling(tx *dbs.Tx, reverseProxyId int64, schedulingJSON []byte) error {
if reverseProxyId <= 0 {

View File

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

View File

@@ -1,6 +1,7 @@
package models
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -63,7 +64,7 @@ func init() {
// UpdateServerBandwidth 写入数据
// 暂时不使用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 {
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)).
Param("bytes", bytes).
Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
InsertOrUpdateQuickly(maps.Map{
"userId": userId,
"serverId": serverId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"userId": userId,
"serverId": serverId,
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
"attackBytes": attackBytes,
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
"attackBytes": dbs.SQL("attackBytes+:attackBytes"),
"countRequests": dbs.SQL("countRequests+:countRequests"),
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
"countAttackRequests": dbs.SQL("countAttackRequests+:countAttackRequests"),
})
}
@@ -110,6 +127,7 @@ func (this *ServerBandwidthStatDAO) FindHourlyBandwidthStats(tx *dbs.Tx, serverI
ones, _, err := this.Query(tx).
Table(this.partialTable(serverId)).
Between("day", timeutil.FormatTime("Ymd", timestamp), timeutil.Format("Ymd")).
Attr("serverId", serverId).
Result(this.maxBytesField(useAvg), "CONCAT(day, '.', SUBSTRING(timeAt, 1, 2)) AS fullTime").
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).
Table(this.partialTable(serverId)).
Between("day", timeFrom[:8], timeTo[:8]).
Attr("serverId", serverId).
Between("CONCAT(day, timeAt)", timeFrom, timeTo).
Count()
@@ -528,6 +547,7 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
// 查询 nth 位置
one, err := this.Query(tx).
Table(this.partialTable(serverId)).
Between("day", timeFrom[:8], timeTo[:8]).
Attr("serverId", serverId).
Between("CONCAT(day, timeAt)", timeFrom, timeTo).
Desc(this.bytesOrderField(useAvg)).
@@ -540,6 +560,191 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
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 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
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) {
var dao = models.NewServerBandwidthStatDAO()
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 {
t.Fatal(err)
}
@@ -28,9 +28,12 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
var tx *dbs.Tx
var count = 1 // 测试时将此值设为一个比较大的数字
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 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 {
t.Fatal(err)
}

View File

@@ -2,27 +2,37 @@ package models
// ServerBandwidthStat 服务峰值带宽统计
type ServerBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节
AvgBytes uint64 `field:"avgBytes"` // 平均流量
TotalBytes uint64 `field:"totalBytes"` // 流量
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节
AvgBytes uint64 `field:"avgBytes"` // 平均流量
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 {
Id any // ID
UserId any // 用户ID
ServerId any // 服务ID
RegionId any // 区域ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHMM
Bytes any // 带宽字节
AvgBytes any // 平均流量
TotalBytes any // 流量
Id any // ID
UserId any // 用户ID
ServerId any // 服务ID
RegionId any // 区域ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHMM
Bytes any // 带宽字节
AvgBytes any // 平均流量
CachedBytes any // 缓存的流量
AttackBytes any // 攻击流量
CountRequests any // 请求数
CountCachedRequests any // 缓存的请求数
CountAttackRequests any // 攻击请求数
TotalBytes any // 总流量
}
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 cacheMap = utils.NewCacheMap()
for _, stat := range stats {
day := timeutil.FormatTime("Ymd", stat.CreatedAt)
hour := timeutil.FormatTime("YmdH", stat.CreatedAt)
timeFrom := timeutil.FormatTime("His", stat.CreatedAt)
timeTo := timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟
var day = timeutil.FormatTime("Ymd", stat.CreatedAt)
var hour = timeutil.FormatTime("YmdH", stat.CreatedAt)
var timeFrom = timeutil.FormatTime("His", stat.CreatedAt)
var timeTo = timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟
// 所属用户
serverUserId, ok := serverUserMap[stat.ServerId]
if !ok {
userId, err := SharedServerDAO.FindServerUserId(tx, stat.ServerId)
if err != nil {
return err
// 用户ID
var serverUserId = stat.UserId
if serverUserId == 0 {
var ok bool
serverUserId, ok = serverUserMap[stat.ServerId]
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).
@@ -195,7 +200,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, reg
// SumUserDaily 获取某天流量总和
// 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)
if regionId > 0 {
query.Attr("regionId", regionId)
@@ -234,7 +239,7 @@ func (this *ServerDailyStatDAO) SumUserTrafficBytesBetweenDays(tx *dbs.Tx, userI
// SumUserMonthly 获取某月流量总和
// 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).
Between("day", month+"01", month+"31").
Attr("userId", userId).
@@ -323,10 +328,10 @@ func (this *ServerDailyStatDAO) SumHourlyStat(tx *dbs.Tx, serverId int64, hour s
return
}
// SumDailyStat 获取某天内的流量
// compatSumDailyStat 获取某天内的流量
// dayFrom 格式为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{}
if userId <= 0 && serverId <= 0 {
@@ -463,7 +468,7 @@ func (this *ServerDailyStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, mont
}
// 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).
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).
@@ -476,7 +481,7 @@ func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFr
dayMap := map[string]*ServerDailyStat{} // day => Stat
for _, one := range ones {
stat := one.(*ServerDailyStat)
var stat = one.(*ServerDailyStat)
dayMap[stat.Day] = stat
}
days, err := utils.RangeDays(dayFrom, dayTo)
@@ -640,7 +645,7 @@ func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month strin
}
// 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).
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).
@@ -651,9 +656,11 @@ func (this *ServerDailyStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hour
return nil, err
}
hourMap := map[string]*ServerDailyStat{} // hour => Stat
var hourMap = map[string]*ServerDailyStat{} // hour => Stat
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
}
hours, err := utils.RangeHours(hourFrom, hourTo)
@@ -665,7 +672,11 @@ func (this *ServerDailyStatDAO) FindHourlyStats(tx *dbs.Tx, serverId int64, hour
if ok {
result = append(result, stat)
} 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 (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing"
"time"
@@ -12,7 +15,7 @@ import (
func TestServerDailyStatDAO_SaveStats(t *testing.T) {
var tx *dbs.Tx
stats := []*pb.ServerDailyStat{
var stats = []*pb.ServerDailyStat{
{
ServerId: 1,
NodeRegionId: 2,
@@ -20,7 +23,7 @@ func TestServerDailyStatDAO_SaveStats(t *testing.T) {
CreatedAt: 1607671488,
},
}
err := NewServerDailyStatDAO().SaveStats(tx, stats)
err := models.NewServerDailyStatDAO().SaveStats(tx, stats)
if err != nil {
t.Fatal(err)
}
@@ -29,7 +32,7 @@ func TestServerDailyStatDAO_SaveStats(t *testing.T) {
func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
var tx *dbs.Tx
stats := []*pb.ServerDailyStat{
var stats = []*pb.ServerDailyStat{
{
ServerId: 1,
NodeRegionId: 3,
@@ -37,7 +40,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
CreatedAt: 1607671488,
},
}
err := NewServerDailyStatDAO().SaveStats(tx, stats)
err := models.NewServerDailyStatDAO().SaveStats(tx, stats)
if err != nil {
t.Fatal(err)
}
@@ -47,7 +50,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
@@ -58,7 +61,7 @@ func TestServerDailyStatDAO_SumHourlyRequests(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
@@ -69,7 +72,7 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
dbs.NotifyReady()
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 {
t.Fatal(err)
}
@@ -78,7 +81,7 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
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 {
t.Fatal(err)
}
@@ -87,7 +90,7 @@ func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
func TestServerDailyStatDAO_FindStatsBetweenDays(t *testing.T) {
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 {
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) {
var dao = NewServerDailyStatDAO()
var dao = models.NewServerDailyStatDAO()
var tx *dbs.Tx
stats, err := dao.FindStatsWithDay(tx, 23, timeutil.Format("Ymd"), "000000", "235900")
if err != nil {

View File

@@ -1 +1,50 @@
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/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -31,6 +32,10 @@ const (
ServerStateDisabled = 0 // 已禁用
)
const (
ModelServerNameMaxLength = 60
)
type ServerDAO dbs.DAO
func NewServerDAO() *ServerDAO {
@@ -121,7 +126,7 @@ func (this *ServerDAO) FindEnabledServerBasic(tx *dbs.Tx, serverId int64) (*Serv
result, err := this.Query(tx).
Pk(serverId).
State(ServerStateEnabled).
Result("id", "name", "description", "isOn", "type", "clusterId", "userId").
Result("id", "name", "description", "isOn", "type", "clusterId", "userId", "groupIds").
Find()
if result == nil {
return nil, err
@@ -205,6 +210,15 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
if IsNotNull(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
if IsNotNull(reverseProxyJSON) {
op.ReverseProxy = reverseProxyJSON
@@ -783,9 +797,11 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
}
if userId > 0 {
query.Attr("userId", userId)
query.UseIndex("userId")
}
if clusterId > 0 {
query.Attr("clusterId", clusterId)
query.UseIndex("clusterId")
}
if auditingFlag == configutils.BoolStateYes {
query.Attr("isAuditing", true)
@@ -839,9 +855,11 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
}
if userId > 0 {
query.Attr("userId", userId)
query.UseIndex("userId")
}
if clusterId > 0 {
query.Attr("clusterId", clusterId)
query.UseIndex("clusterId")
}
if auditingFlag == 1 {
query.Attr("isAuditing", true)
@@ -1009,12 +1027,12 @@ func (this *ServerDAO) ComposeServerConfigWithServerId(tx *dbs.Tx, serverId int6
if server == nil {
return nil, ErrNotFound
}
return this.ComposeServerConfig(tx, server, ignoreCertData, nil, forNode, false)
return this.ComposeServerConfig(tx, server, ignoreCertData, nil, nil, forNode, false)
}
// ComposeServerConfig 构造服务的Config
// 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 {
return nil, ErrNotFound
}
@@ -1034,12 +1052,14 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
config.UserId = int64(server.UserId)
config.Type = server.Type
config.IsOn = server.IsOn
config.Name = server.Name
config.Description = server.Description
if !forNode {
config.Name = server.Name
config.Description = server.Description
}
var groupConfig *serverconfigs.ServerGroupConfig
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 {
return nil, err
}
@@ -1098,7 +1118,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil {
return nil, err
}
config.HTTP = httpConfig
if !forNode || httpConfig.IsOn {
config.HTTP = httpConfig
}
}
// HTTPS
@@ -1109,18 +1131,20 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
return nil, err
}
// SSL
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 && !ignoreCerts {
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, httpsConfig.SSLPolicyRef.SSLPolicyId, false, cacheMap)
if err != nil {
return nil, err
if !forNode || httpsConfig.IsOn {
// SSL
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 && !ignoreCerts {
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, httpsConfig.SSLPolicyRef.SSLPolicyId, false, dataMap, cacheMap)
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
@@ -1130,7 +1154,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil {
return nil, err
}
config.TCP = tcpConfig
if !forNode || tcpConfig.IsOn {
config.TCP = tcpConfig
}
}
// TLS
@@ -1141,18 +1167,20 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
return nil, err
}
// SSL
if tlsConfig.SSLPolicyRef != nil && !ignoreCerts {
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, tlsConfig.SSLPolicyRef.SSLPolicyId, false, cacheMap)
if err != nil {
return nil, err
if !forNode || tlsConfig.IsOn {
// SSL
if tlsConfig.SSLPolicyRef != nil && !ignoreCerts {
sslPolicyConfig, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, tlsConfig.SSLPolicyRef.SSLPolicyId, false, dataMap, cacheMap)
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
@@ -1162,7 +1190,9 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil {
return nil, err
}
config.Unix = unixConfig
if !forNode || unixConfig.IsOn {
config.Unix = unixConfig
}
}
// UDP
@@ -1172,13 +1202,15 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil {
return nil, err
}
config.UDP = udpConfig
if !forNode || udpConfig.IsOn {
config.UDP = udpConfig
}
}
// Web
if !forList {
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 {
return nil, err
}
@@ -1196,14 +1228,18 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
if err != nil {
return nil, err
}
config.ReverseProxyRef = reverseProxyRef
if !forNode || reverseProxyRef.IsOn {
config.ReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
if err != nil {
return nil, err
}
if reverseProxyConfig != nil {
config.ReverseProxy = reverseProxyConfig
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil {
return nil, err
}
if reverseProxyConfig != nil {
if !forNode || reverseProxyConfig.IsOn {
config.ReverseProxy = reverseProxyConfig
}
}
}
}
}
@@ -1427,7 +1463,7 @@ func (this *ServerDAO) CountEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64)
Count()
}
// FindAllEnabledServersWithWebIds 查找使用某个缓存策略的所有服务
// FindAllEnabledServersWithWebIds 通过WebId查找服务
func (this *ServerDAO) FindAllEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64) (result []*Server, err error) {
if len(webIds) == 0 {
return
@@ -1435,6 +1471,7 @@ func (this *ServerDAO) FindAllEnabledServersWithWebIds(tx *dbs.Tx, webIds []int6
_, err = this.Query(tx).
State(ServerStateEnabled).
Attr("webId", webIds).
UseIndex("webId").
Reuse(false).
AscPk().
Slice(&result).
@@ -1557,12 +1594,16 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
}
// 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 {
return
}
one, err := this.Query(tx).
var query = this.Query(tx)
if userId > 0 {
query.Attr("userId", userId)
}
one, err := query.
State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :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, ".")
if dotIndex > 0 {
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).
Where("JSON_CONTAINS(plainServerNames, :domain)").
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)
}
// 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 同步服务所在的集群
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)
}
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)
}
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")
@@ -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) {
models.SharedServerDAO = models.NewServerDAO()

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -279,7 +280,7 @@ func (this *ServerGroupDAO) InitGroupWeb(tx *dbs.Tx, groupId int64) (int64, erro
}
// 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 {
cacheMap = utils.NewCacheMap()
}
@@ -324,7 +325,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
}
config.HTTPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -341,7 +342,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
}
config.TCPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -358,7 +359,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
}
config.UDPReverseProxyRef = reverseProxyRef
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, dataMap, cacheMap)
if err != nil {
return nil, err
}
@@ -369,7 +370,7 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forLis
// web
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 {
return nil, err
}
@@ -423,6 +424,18 @@ func (this *ServerGroupDAO) ExistsGroup(tx *dbs.Tx, groupId int64) (bool, error)
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 通知更新
func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId)

View File

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

View File

@@ -6,12 +6,15 @@ import (
"errors"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"strings"
"time"
)
@@ -201,7 +204,7 @@ func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx,
// ComposeCertConfig 组合配置
// 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 {
cacheMap = utils.NewCacheMap()
}
@@ -227,8 +230,17 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
config.Name = cert.Name
config.Description = cert.Description
if !ignoreData {
config.CertData = cert.CertData
config.KeyData = cert.KeyData
if dataMap != nil {
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.TimeBeginAt = int64(cert.TimeBeginAt)
@@ -236,7 +248,13 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
// OCSP
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.OCSPError = cert.OcspError
@@ -267,8 +285,8 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, ignoreData b
}
// CountCerts 计算符合条件的证书数量
func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64) (int64, error) {
query := this.Query(tx).
func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userId int64, domains []string) (int64, error) {
var query = this.Query(tx).
State(SSLCertStateEnabled)
if isCA {
query.Attr("isCA", true)
@@ -293,12 +311,19 @@ func (this *SSLCertDAO) CountCerts(tx *dbs.Tx, isCA bool, isAvailable bool, isEx
// 只查询管理员上传的
query.Attr("userId", 0)
}
// 域名
err := this.buildDomainSearchingQuery(query, domains)
if err != nil {
return 0, err
}
return query.Count()
}
// 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) {
query := this.Query(tx).
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) {
var query = this.Query(tx).
State(SSLCertStateEnabled)
if isCA {
query.Attr("isCA", true)
@@ -324,6 +349,12 @@ func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isE
query.Attr("userId", 0)
}
// 域名
err = this.buildDomainSearchingQuery(query, domains)
if err != nil {
return nil, err
}
ones, err := query.
ResultPk().
DescPk().
@@ -334,7 +365,7 @@ func (this *SSLCertDAO) ListCertIds(tx *dbs.Tx, isCA bool, isAvailable bool, isE
return nil, err
}
result := []int64{}
var result = []int64{}
for _, one := range ones {
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)
_, err = this.Query(tx).
State(SSLCertStateEnabled).
Attr("isOn", true).
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("today", timeutil.Format("Y-m-d")).
@@ -633,3 +665,73 @@ func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
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"
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
@@ -77,7 +78,7 @@ func (this *SSLPolicyDAO) FindEnabledSSLPolicy(tx *dbs.Tx, id int64) (*SSLPolicy
}
// 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 {
cacheMap = utils.NewCacheMap()
}
@@ -111,7 +112,7 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignore
}
if len(refs) > 0 {
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 {
return nil, err
}
@@ -133,7 +134,7 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, ignore
}
if len(refs) > 0 {
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 {
return nil, err
}

View File

@@ -114,6 +114,20 @@ func (this *NodeClusterTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, clusterId
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 清理历史数据
func (this *NodeClusterTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
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) {
_, err = this.Query(tx).
Asc().
AscPk().
Limit(size).
Slice(&result).
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
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -26,6 +27,9 @@ const (
UserBandwidthStatTablePartials = 20
)
var fullDataMap = map[string]bool{} // month => bool
var fullDataLocker = &sync.Mutex{}
func init() {
dbs.OnReadyDone(func() {
// 清理数据任务
@@ -61,7 +65,7 @@ func init() {
}
// 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 {
// 如果用户ID不大于0则说明服务不属于任何用户此时不需要处理
return nil
@@ -71,18 +75,33 @@ func (this *UserBandwidthStatDAO) UpdateUserBandwidth(tx *dbs.Tx, userId int64,
Table(this.partialTable(userId)).
Param("bytes", bytes).
Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
Param("countRequests", countRequests).
Param("countCachedRequests", countCachedRequests).
Param("countAttackRequests", countAttackRequests).
InsertOrUpdateQuickly(maps.Map{
"userId": userId,
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"userId": userId,
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
"attackBytes": attackBytes,
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
"attackBytes": dbs.SQL("attackBytes+:attackBytes"),
"countRequests": dbs.SQL("countRequests+:countRequests"),
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
"countAttackRequests": dbs.SQL("countAttackRequests+:countAttackRequests"),
})
}
@@ -320,6 +339,127 @@ func (this *UserBandwidthStatDAO) FindDistinctUserIds(tx *dbs.Tx, dayFrom string
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 清理过期数据
func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error {
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
}
// 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) {
var dao = models.NewUserBandwidthStatDAO()
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 {
t.Fatal(err)
}
@@ -93,3 +93,13 @@ func TestUserBandwidthStatDAO_FindPercentileBetweenDays(t *testing.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 用户月带宽峰值
type UserBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHII
Bytes uint64 `field:"bytes"` // 带宽
TotalBytes uint64 `field:"totalBytes"` // 总流量
AvgBytes uint64 `field:"avgBytes"` // 平均流量
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
RegionId uint32 `field:"regionId"` // 区域ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHII
Bytes uint64 `field:"bytes"` // 带宽
TotalBytes uint64 `field:"totalBytes"` // 总流量
AvgBytes uint64 `field:"avgBytes"` // 平均流量
CachedBytes uint64 `field:"cachedBytes"` // 缓存的流量
AttackBytes uint64 `field:"attackBytes"` // 攻击流量
CountRequests uint64 `field:"countRequests"` // 请求数
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
CountAttackRequests uint64 `field:"countAttackRequests"` // 攻击请求数
}
type UserBandwidthStatOperator struct {
Id any // ID
UserId any // 用户ID
RegionId any // 区域ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHII
Bytes any // 带宽
TotalBytes any // 总流量
AvgBytes any // 平均流量
Id any // ID
UserId any // 用户ID
RegionId any // 区域ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHII
Bytes any // 带宽
TotalBytes any // 总流量
AvgBytes any // 平均流量
CachedBytes any // 缓存的流量
AttackBytes any // 攻击流量
CountRequests any // 请求数
CountCachedRequests any // 缓存的请求数
CountAttackRequests any // 攻击请求数
}
func NewUserBandwidthStatOperator() *UserBandwidthStatOperator {

View File

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

View File

@@ -2,6 +2,7 @@ package dbutils
import (
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
"net"
"strings"
)
@@ -93,3 +94,36 @@ func IsLocalAddr(addr string) bool {
}
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: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
}

View File

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

View File

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

View File

@@ -5,6 +5,7 @@ import (
"github.com/iwind/TeaGo/files"
stringutil "github.com/iwind/TeaGo/utils/string"
"regexp"
"sync"
)
var SharedDeployManager = NewDeployManager()
@@ -12,9 +13,12 @@ var SharedDeployManager = NewDeployManager()
// DeployManager 节点部署文件管理器
// 如果节点部署文件有变化需要重启API节点以便于生效
type DeployManager struct {
dir string
dir string
nodeFiles []*DeployFile
nsNodeFiles []*DeployFile
locker sync.Mutex
}
// NewDeployManager 获取新节点部署文件管理器
@@ -29,24 +33,27 @@ func NewDeployManager() *DeployManager {
// LoadNodeFiles 加载所有边缘节点文件
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
this.locker.Lock()
defer this.locker.Unlock()
if len(this.nodeFiles) > 0 {
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() {
name := file.Name()
var name = file.Name()
if !reg.MatchString(name) {
continue
}
matches := reg.FindStringSubmatch(name)
osName := matches[1]
arch := matches[2]
version := matches[3]
var matches = reg.FindStringSubmatch(name)
var osName = matches[1]
var arch = matches[2]
var version = matches[3]
key := osName + "_" + arch
var key = osName + "_" + arch
oldFile, ok := keyMap[key]
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
continue
@@ -59,7 +66,7 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
}
}
result := []*DeployFile{}
var result = []*DeployFile{}
for _, v := range keyMap {
result = append(result, v)
}
@@ -81,24 +88,27 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
// LoadNSNodeFiles 加载所有NS节点安装文件
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
this.locker.Lock()
defer this.locker.Unlock()
if len(this.nsNodeFiles) > 0 {
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() {
name := file.Name()
var name = file.Name()
if !reg.MatchString(name) {
continue
}
matches := reg.FindStringSubmatch(name)
osName := matches[1]
arch := matches[2]
version := matches[3]
var matches = reg.FindStringSubmatch(name)
var osName = matches[1]
var arch = matches[2]
var version = matches[3]
key := osName + "_" + arch
var key = osName + "_" + arch
oldFile, ok := keyMap[key]
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
continue
@@ -111,7 +121,7 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
}
}
result := []*DeployFile{}
var result = []*DeployFile{}
for _, v := range keyMap {
result = append(result, v)
}
@@ -130,3 +140,12 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile {
}
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 {
var rpcServer *grpc.Server
var options = []grpc.ServerOption{
grpc.MaxRecvMsgSize(128 * 1024 * 1024),
grpc.MaxSendMsgSize(128 * 1024 * 1024),
grpc.MaxRecvMsgSize(512 << 20),
grpc.MaxSendMsgSize(512 << 20),
grpc.UnaryInterceptor(this.unaryInterceptor),
}
@@ -306,13 +306,27 @@ func (this *APINode) checkDB() error {
logs.Println("[API_NODE]" + 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
if Tea.IsTesting() {
maxTries = 600
}
for i := 0; i <= maxTries; i++ {
_, err := db.Exec("SELECT 1")
_, err = db.Exec("SELECT 1")
if err != nil {
if i == maxTries-1 {
return err
@@ -741,6 +755,41 @@ func (this *APINode) listenSock() error {
"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)
}
{
var instance = this.serviceInstance(&services.UpdatingServerListService{}).(*services.UpdatingServerListService)
pb.RegisterUpdatingServerListServiceServer(server, instance)
this.rest(instance)
}
APINodeServicesRegister(this, server)
// TODO check service names

View File

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

View File

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

View File

@@ -232,6 +232,12 @@ func (this *ACMETaskService) CreateACMETask(ctx context.Context, req *pb.CreateA
req.AuthType = acme.AuthTypeDNS
}
if adminId > 0 {
if req.UserId > 0 {
userId = req.UserId
}
}
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)
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{
Id: int64(task.Id),
IsOn: task.IsOn,
@@ -425,5 +437,6 @@ func (this *ACMETaskService) FindEnabledACMETask(ctx context.Context, req *pb.Fi
AcmeUser: pbACMEUser,
AuthType: task.AuthType,
AuthURL: task.AuthURL,
SslCert: pbCert,
}}, nil
}

View File

@@ -22,6 +22,12 @@ func (this *ACMEUserService) CreateACMEUser(ctx context.Context, req *pb.CreateA
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)
if err != nil {
return nil, err

View File

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

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