Compare commits

...

161 Commits

Author SHA1 Message Date
刘祥超
529016d4d5 版本号更改为1.2.5 2023-07-26 15:30:37 +08:00
刘祥超
63942bfb08 将版本号修改为1.2.4 2023-07-26 10:19:02 +08:00
刘祥超
f4e4f32f9c 修复SysLocker无法写入新Key的问题 2023-07-26 10:18:52 +08:00
刘祥超
0a3c740502 版本号修改为1.2.3 2023-07-25 13:17:59 +08:00
刘祥超
9a3438e066 优化IP名单使用IP搜索查询速度 2023-07-25 12:26:12 +08:00
刘祥超
814b82e1b6 优化TOA相关代码 2023-07-24 15:33:44 +08:00
刘祥超
89cfd175cd 优化TOA相关API 2023-07-24 09:56:43 +08:00
刘祥超
860816719e 单个节点所在多个集群共用一个缓存策略时只加载其中一个 2023-07-20 16:54:34 +08:00
刘祥超
caa936f0ac 大幅提升SysLocker自增性能 2023-07-20 14:25:42 +08:00
刘祥超
97836a89eb 优化代码 2023-07-19 18:49:23 +08:00
刘祥超
84483dce61 版本号更改为1.2.2 2023-07-18 14:33:53 +08:00
刘祥超
a4eb7a47f3 更新SQL 2023-07-16 19:12:10 +08:00
刘祥超
20c84d7fe5 手动同步集群任务后把所有相关任务标记为已完成 2023-07-14 10:04:44 +08:00
刘祥超
9d5acd2b36 优化代码 2023-07-12 17:10:33 +08:00
刘祥超
7508f6b92b 增加页面优化相关API 2023-07-11 19:46:00 +08:00
刘祥超
379030fe71 版本号改为1.2.1 2023-07-09 17:38:09 +08:00
刘祥超
10027eea20 缓存策略移除“容纳Key数量”选项 2023-07-08 18:50:58 +08:00
刘祥超
69f25a176b 提交SQL 2023-07-07 18:52:37 +08:00
刘祥超
ac19f06b6c 网站列表增加QPS和攻击QPS信息 2023-07-07 18:51:36 +08:00
刘祥超
87a81f59c7 修复查询网站日流量统计时可能不兼容MySQL8的问题 2023-07-07 17:35:23 +08:00
刘祥超
7389e5e54b 远程安装时可以覆盖运行中的文件 2023-07-07 15:59:51 +08:00
刘祥超
e6792b8188 优化自定义页面设置,页面URL不再支持填写本地文件 2023-07-07 11:48:48 +08:00
刘祥超
a037546cfa 优化代码 2023-07-07 09:52:53 +08:00
刘祥超
8efaacf1ef 国家/地区、省份等相关表增加真实ID字段,防止数据表被用户修改时无法对应 2023-07-07 09:52:46 +08:00
刘祥超
a38dd1cef8 “集群设置 -- 网站设置”增加“允许记录访问日志”选项 2023-07-05 15:29:11 +08:00
刘祥超
77521112d0 试用 executils.LookPath()代替 exec.LookPath() 2023-07-05 11:34:52 +08:00
刘祥超
4f9a5d238c 优化本地mysql服务自动启动逻辑 2023-07-05 11:14:51 +08:00
刘祥超
d5fb39ed50 更新TeaGo库 2023-07-05 09:25:27 +08:00
刘祥超
58a84083ae 优化自增锁性能 2023-07-04 22:02:17 +08:00
刘祥超
9f564a4739 重写规则API支持用户操作 2023-07-04 18:31:12 +08:00
刘祥超
c20accbf58 减少在自增锁中生成的sql statements 2023-07-04 14:42:14 +08:00
刘祥超
3f21b3148e 优化代码 2023-07-03 17:12:24 +08:00
刘祥超
74e909a501 增加清空节点同步任务、清空DNS同步任务API 2023-07-02 17:29:19 +08:00
刘祥超
4150ee1b47 优化自增锁算法 2023-07-02 15:27:49 +08:00
刘祥超
df04de2151 修复测试用例 2023-07-02 15:25:13 +08:00
刘祥超
4dc5d9aa7e 修复自动生成的用户没有绑定集群、用户名不规范的问题 2023-07-02 14:30:46 +08:00
刘祥超
0ef7e6ccd8 增加部分数据清理周期设置 2023-07-01 17:54:40 +08:00
刘祥超
ed2b831e5a 查找当前API节点版本中增加角色 2023-07-01 15:09:54 +08:00
刘祥超
5d392ecd43 优化代码 2023-06-30 19:06:55 +08:00
刘祥超
ea147d7506 优化代码 2023-06-30 19:01:47 +08:00
刘祥超
b45136c2c8 优化代码 2023-06-30 18:54:45 +08:00
刘祥超
530e1513ec 日志API增加多语言代号参数 2023-06-30 18:10:11 +08:00
刘祥超
6c60677b72 添加多语言最基础代码 2023-06-28 09:11:20 +08:00
刘祥超
a1bec5e578 创建Web配置时自动设置访客IP获取方式为“直接获取” 2023-06-23 17:05:52 +08:00
刘祥超
9dece058d9 优化查询所有集群性能 2023-06-23 16:23:21 +08:00
刘祥超
89df6ae6bf 优化集群列表性能 2023-06-23 16:15:22 +08:00
刘祥超
85b6e6428c 源站支持HTTP/2 2023-06-23 11:44:02 +08:00
刘祥超
0df204a1df 初始化时修改默认生成的用户名,并将用户自动关联到默认集群 2023-06-21 11:51:07 +08:00
刘祥超
ecef94b700 增加简化版的创建TCP网站API 2023-06-18 17:14:24 +08:00
刘祥超
a493bbb280 增加简化版的创建HTTP网站API 2023-06-18 16:20:00 +08:00
刘祥超
eee902abec 优化错误提示 2023-06-16 08:17:00 +08:00
刘祥超
2aceb4fb4d 版本号改为1.2.0 2023-06-12 14:42:26 +08:00
刘祥超
c1bbcc8dab 已停用的节点不计算在离线节点里 2023-06-12 14:10:18 +08:00
刘祥超
262f8a5594 已经停用的节点不提示需要升级 2023-06-12 14:04:50 +08:00
刘祥超
a85b49a377 智能DNS实现DoH功能 2023-06-11 17:57:31 +08:00
刘祥超
75e353db0e 初步实现对象存储源站 2023-06-07 17:25:20 +08:00
刘祥超
ccbb14836e 修复因serverId传入0而可能删除WAF策略的问题 2023-06-06 15:03:18 +08:00
刘祥超
7fbc61aa21 改进DNS域名解析相关函数 2023-06-05 12:36:29 +08:00
刘祥超
8b804cb500 修复一个测试用例 2023-06-04 09:38:13 +08:00
刘祥超
3ddb95731a Update sql.json 2023-06-03 09:08:44 +08:00
刘祥超
beeb46ab7f 修复节点IP为IPv6时无法健康检查的问题 2023-06-02 14:46:38 +08:00
刘祥超
a65255e4e5 优化代码 2023-06-01 18:08:45 +08:00
刘祥超
b7768ea0c0 初步实现HTTP3 2023-06-01 17:46:10 +08:00
刘祥超
9d2ecf6822 提供用户某日刷新/预热缓存数量查询API 2023-05-28 18:00:51 +08:00
刘祥超
1a6d160a33 优化创建缓存任务时域名检查速度 2023-05-28 17:44:27 +08:00
刘祥超
b69132e1ca 版本号改为1.1.0 2023-05-28 16:06:53 +08:00
刘祥超
19890c209f 优化健康检查代码 2023-05-28 15:13:15 +08:00
刘祥超
1534436435 ACMETaskService.FindEnabledACMETask()返回信息中增加关联的证书信息 2023-05-25 14:55:46 +08:00
刘祥超
c087d1cba2 Update sql.json 2023-05-25 14:55:09 +08:00
刘祥超
cfc2ec5e4b 优化代码 2023-05-23 19:50:28 +08:00
刘祥超
af9c8523e9 实现集群CC防护策略设置 2023-05-23 19:16:30 +08:00
刘祥超
00977cf33e 实现集群自定义页面 2023-05-22 17:30:33 +08:00
刘祥超
fc2d018207 优化自定义页面配置存储 2023-05-22 10:04:46 +08:00
刘祥超
8569eebfee 修复使用localhost连接数据库时不能自动尝试启动的问题 2023-05-20 16:58:14 +08:00
刘祥超
73d72f0d33 HTTP Header中支持设置非标Header 2023-05-19 19:54:10 +08:00
刘祥超
c4b8540171 HTTP Header - CORS跨域设置增加多个选项 2023-05-19 16:34:24 +08:00
刘祥超
85219ac2ef 增加复制节点动作API 2023-05-19 11:12:24 +08:00
刘祥超
6976454bde 实现基础的智能调度 2023-05-17 18:42:21 +08:00
刘祥超
813ce44ceb 修复AscPk()写成Asc()的问题 2023-05-12 15:34:18 +08:00
刘祥超
294b57ca60 非超级用户不提示弱密码管理员 2023-05-06 14:04:21 +08:00
刘祥超
22010190b2 智能 DNS实现健康检查 2023-05-03 17:09:55 +08:00
刘祥超
cc4cd9c620 防盗链增加”同时检查Origin选项“ 2023-05-02 17:11:22 +08:00
刘祥超
5df9c0f1fd 检查节点认证时增加状态参数 2023-04-26 11:26:42 +08:00
刘祥超
dc3594a08d 集群健康检查可以同时检查单节点的多个IP 2023-04-26 10:50:29 +08:00
刘祥超
49ba1336cd 修复用户可能无法删除IP的问题 2023-04-25 11:28:04 +08:00
刘祥超
96db5af237 修复用户端无法查看IP名单的Bug 2023-04-25 11:18:09 +08:00
刘祥超
476ff91bf8 版本号修改为1.0.4 2023-04-24 10:18:26 +08:00
刘祥超
ac6b10489e DNSPod支持自定义线路分组 2023-04-24 09:37:26 +08:00
刘祥超
9352e1837f 创建初始化用户 2023-04-23 20:13:55 +08:00
刘祥超
ddec102d18 远程升级API节点时自动上传边缘节点安装文件 2023-04-23 19:42:51 +08:00
刘祥超
0d50b9b0cc 创建ACME用户、ACME任务时可以指定平台用户 2023-04-23 15:00:13 +08:00
刘祥超
20b4b47eea 优化edgeIPItems索引 2023-04-23 09:44:06 +08:00
刘祥超
ee8396c760 修复在节点列表中不能同时使用关键词和排序的问题 2023-04-21 15:27:24 +08:00
刘祥超
c3fa6a753a 修复只有一个泛域名时无法查询匹配证书的问题 2023-04-21 10:41:20 +08:00
刘祥超
fbe4de2e94 节点版本号修改为1.1.0 2023-04-19 21:02:01 +08:00
刘祥超
f5c7108799 IP库查询提供更多信息 2023-04-19 20:36:48 +08:00
刘祥超
5825a7e654 修复一处访问日志可能无法正确获得对应日期的问题 2023-04-18 17:54:01 +08:00
刘祥超
a6911117af 优化可用内存检查 2023-04-11 18:52:43 +08:00
刘祥超
b428db4f5e 版本号改为1.1.0 2023-04-10 21:03:31 +08:00
刘祥超
e4145a2059 优化启动速度 2023-04-10 20:57:38 +08:00
刘祥超
af13357985 创建缓存任务接口增加参数校验 2023-04-10 17:13:20 +08:00
刘祥超
1b949bd056 版本号修改为1.0.1 2023-04-10 09:18:12 +08:00
刘祥超
c4e415a72f 修复一个单词拼写错误/如果创建服务时没有指定服务名,则自动取第一个域名作为服务名 2023-04-09 20:11:36 +08:00
刘祥超
39cb95184d 查询弱密码管理员时只查询已启用的管理员 2023-04-09 17:31:09 +08:00
刘祥超
a7abca6c09 Update sql.json 2023-04-09 17:23:37 +08:00
刘祥超
894eff89ba 去除不需要的接口 2023-04-09 17:04:32 +08:00
刘祥超
35558f1d38 版本号更改为1.0.0 2023-04-09 16:19:52 +08:00
刘祥超
5a93ec0e32 增加服务之间拷贝配置的API(开源版本只有定义,没有完全实现) 2023-04-09 16:01:23 +08:00
刘祥超
73164de93e 查询快过期证书时,只查询启用的 2023-04-08 09:15:03 +08:00
刘祥超
199349084e 提供批量更新服务配置API(阶段性提交) 2023-04-06 20:49:22 +08:00
刘祥超
648fc2cac3 审计日志列表增加级别筛选 2023-04-06 10:06:56 +08:00
刘祥超
43f34950f3 自动检查管理员弱密码并提醒 2023-04-04 17:26:08 +08:00
刘祥超
1f0182e4a5 优化错误提示 2023-04-04 15:56:44 +08:00
刘祥超
3f972571b0 5秒盾策略变化时只更新策略配置 2023-04-03 16:11:48 +08:00
刘祥超
0618ca9f8a 优化操作IP条目时检查用户ID的相关代码 2023-04-03 10:02:17 +08:00
刘祥超
efd0823b25 上传SQL 2023-04-01 21:46:54 +08:00
刘祥超
af5ca9faf5 修复删除IP名单中IP时状态设置错误的问题 2023-04-01 20:48:47 +08:00
刘祥超
87c5eeb829 可以批量上传IP名单 2023-03-31 21:42:15 +08:00
刘祥超
df775272be 提供修改网站名称的接口 2023-03-31 15:30:22 +08:00
刘祥超
dbeabe4379 节点中增加授权信息 2023-03-31 12:39:01 +08:00
刘祥超
dd33504416 IP库文件可以加密 2023-03-30 20:00:22 +08:00
刘祥超
d45dca4edb IP制品列表中增加文件尺寸 2023-03-29 20:09:00 +08:00
刘祥超
b4472271ce 优化证书到期提醒等相关消息 2023-03-28 16:52:04 +08:00
刘祥超
138eddf771 修复发送站内消息时将标题作为内容的Bug 2023-03-28 16:25:18 +08:00
刘祥超
f0667abe55 删除edgeServers表中的state索引,防止查询时产生索引冲突 2023-03-27 17:14:48 +08:00
刘祥超
873af38807 优化服务列表查询 2023-03-27 17:14:12 +08:00
刘祥超
9bf46af088 增加默认CC设置 2023-03-26 12:41:01 +08:00
刘祥超
3a3b5bca20 上传单个证书时也可以选择所属用户 2023-03-26 12:24:31 +08:00
刘祥超
4806025f89 实现自动匹配证书和批量选择证书功能 2023-03-25 20:51:08 +08:00
刘祥超
d7c757a2a1 增加批量上传证书接口、使用域名查询证书接口 2023-03-24 19:07:43 +08:00
刘祥超
3e8873d828 修复查看服务24小时流量统计会产生panic的问题 2023-03-23 15:45:03 +08:00
刘祥超
84484b6538 优化服务带宽查询速度 2023-03-23 11:23:16 +08:00
刘祥超
d36e9e80ee 上传流量数据时同时上传服务所属用户ID 2023-03-22 19:33:25 +08:00
刘祥超
1fb831ca58 修复测试用例 2023-03-22 19:10:52 +08:00
刘祥超
5e20553602 合并部分流量查询和带宽查询 2023-03-22 17:54:44 +08:00
刘祥超
0f83d8ec66 导出SQL结构时使用embed取代生成sql.go 2023-03-22 11:19:58 +08:00
刘祥超
e45a6cbcb5 优化域名查询程序 2023-03-21 11:38:20 +08:00
刘祥超
ba1fd07555 增加edge-api token --role=[admin|user|api]命令用来快速查询节点Token 2023-03-19 21:24:24 +08:00
刘祥超
a70b4bfaf3 更新相关库 2023-03-19 17:51:21 +08:00
刘祥超
9cf47ae1af DNS集群增加自动检测端口选项 2023-03-19 17:44:56 +08:00
刘祥超
7f58d65a57 修复DataMap无法在多个节点之间共享的问题 2023-03-19 10:26:05 +08:00
刘祥超
4d40dd03de 优化节点压缩程序 2023-03-18 22:44:23 +08:00
刘祥超
e3ce79c9fc 增加RPC消息最大尺寸到512MB 2023-03-18 22:44:04 +08:00
刘祥超
f543edac1a 节点组合配置时服务间可以共用证书数据 2023-03-18 22:18:13 +08:00
刘祥超
1ce11a5745 优化服务配置组合 2023-03-18 19:52:42 +08:00
刘祥超
ab56c7451a DNS解析发生变化时立即触发同步任务 2023-03-18 16:53:08 +08:00
刘祥超
9800bbb661 修复无法同时对相同对象执行多次DNS解析任务的问题 2023-03-18 16:40:00 +08:00
刘祥超
8c4d2e7301 查询节点DNS信息时可以区分节点是否已安装 2023-03-18 16:05:10 +08:00
刘祥超
2c17675b6a 增加分隔关键词函数 2023-03-18 11:10:44 +08:00
刘祥超
3b30705f33 在API节点启动时,如果无法连接到本地MySQL数据库,则尝试启动固定位置上的MySQL 2023-03-17 16:02:37 +08:00
刘祥超
4cd9c5071d 版本号更改为0.6.5 2023-03-17 15:53:52 +08:00
刘祥超
763a72d526 版本号变更为0.6.4.2 2023-03-16 08:59:59 +08:00
刘祥超
bd762ad10b 读取节点列表时可以按照连接数排序 2023-03-15 17:57:49 +08:00
刘祥超
56574ea3d9 节点看板数据中增加当月、昨日、今日流量 2023-03-15 17:02:09 +08:00
刘祥超
6a31605519 集群看板数据中增加当月流量 2023-03-15 16:24:36 +08:00
刘祥超
c7abeeaf07 优化代码 2023-03-14 09:17:05 +08:00
刘祥超
c11483ec6d 允许API之间相互调用 2023-03-13 16:15:31 +08:00
刘祥超
c3713cefc9 生成数据库结构sql.go文件的同时生成sql.json 2023-03-13 14:32:39 +08:00
刘祥超
2098bd4d32 版本号改为0.6.5 2023-03-13 14:29:34 +08:00
刘祥超
7a6a02284e 修复搜索引擎IP库可能无法升级的Bug 2023-03-13 10:36:41 +08:00
刘祥超
c749a7b088 版本号改为0.6.4.1 2023-03-13 10:36:03 +08:00
217 changed files with 238471 additions and 1354 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", "http2Enabled", "http3Enabled" ]

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

@@ -52,7 +52,7 @@ func main() {
return
}
unzip := helpers.NewUnzip(zipPath, targetPath)
var unzip = helpers.NewUnzip(zipPath, targetPath)
err := unzip.Run()
if err != nil {
stderr("ERROR: " + err.Error())

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")
}

23
go.mod
View File

@@ -10,25 +10,26 @@ require (
github.com/andybalholm/brotli v1.0.4
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/fsnotify/fsnotify v1.6.0
github.com/go-acme/lego/v4 v4.10.2
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/TeaGo v0.0.0-20230704135818-4a5646ab1f5b
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
github.com/miekg/dns v1.1.50
github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0
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/crypto v0.5.0
golang.org/x/net v0.8.0
golang.org/x/sys v0.8.0
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -40,13 +41,15 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/smartwalle/crypto4go v1.0.2 // indirect
github.com/tdewolff/minify/v2 v2.12.7 // indirect
github.com/tdewolff/parse/v2 v2.6.6 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
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

61
go.sum
View File

@@ -12,13 +12,14 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -30,6 +31,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -38,13 +41,16 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
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,12 +84,8 @@ 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/TeaGo v0.0.0-20230704135818-4a5646ab1f5b h1:yYUaxnc04uzfr7C9HBN52ZZvcQomND+C5aZTpjOUYFI=
github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -99,10 +101,11 @@ github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -143,12 +146,20 @@ github.com/smartwalle/crypto4go v1.0.2 h1:9DUEOOsPhmp00438L4oBdcL8EZG1zumecft5bW
github.com/smartwalle/crypto4go v1.0.2/go.mod h1:LQ7vCZIb7BE5+MuMtJBuO8ORkkQ01m4DXDBWPzLbkMY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tdewolff/minify/v2 v2.12.7 h1:pBzz2tAfz5VghOXiQIsSta6srhmTeinQPjRDHWoumCA=
github.com/tdewolff/minify/v2 v2.12.7/go.mod h1:ZRKTheiOGyLSK8hOZWWv+YoJAECzDivNgAlVYDHp/Ws=
github.com/tdewolff/parse/v2 v2.6.6 h1:Yld+0CrKUJaCV78DL1G2nk3C9lKrxyRTux5aaK/AkDo=
github.com/tdewolff/parse/v2 v2.6.6/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
@@ -165,8 +176,8 @@ golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
@@ -179,8 +190,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 +205,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 +214,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 +236,19 @@ 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.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.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 +257,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"
Version = "1.2.5"
ProductName = "Edge API"
ProcessName = "edge-api"
@@ -18,7 +18,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.6.4"
NodeVersion = "1.2.5"
// 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

@@ -2,6 +2,22 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
AdminField_Id dbs.FieldName = "id" // ID
AdminField_IsOn dbs.FieldName = "isOn" // 是否启用
AdminField_Username dbs.FieldName = "username" // 用户名
AdminField_Password dbs.FieldName = "password" // 密码
AdminField_Fullname dbs.FieldName = "fullname" // 全名
AdminField_IsSuper dbs.FieldName = "isSuper" // 是否为超级管理员
AdminField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
AdminField_UpdatedAt dbs.FieldName = "updatedAt" // 修改时间
AdminField_State dbs.FieldName = "state" // 状态
AdminField_Modules dbs.FieldName = "modules" // 允许的模块
AdminField_CanLogin dbs.FieldName = "canLogin" // 是否可以登录
AdminField_Theme dbs.FieldName = "theme" // 模板设置
AdminField_Lang dbs.FieldName = "lang" // 语言代号
)
// Admin 管理员
type Admin struct {
Id uint32 `field:"id"` // ID
@@ -16,6 +32,7 @@ type Admin struct {
Modules dbs.JSON `field:"modules"` // 允许的模块
CanLogin bool `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置
Lang string `field:"lang"` // 语言代号
}
type AdminOperator struct {
@@ -31,6 +48,7 @@ type AdminOperator struct {
Modules any // 允许的模块
CanLogin any // 是否可以登录
Theme any // 模板设置
Lang any // 语言代号
}
func NewAdminOperator() *AdminOperator {

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

@@ -335,6 +335,7 @@ func (this *APINodeDAO) UpdateAPINodeStatus(tx *dbs.Tx, apiNodeId int64, statusJ
func (this *APINodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(APINodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).

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

@@ -210,6 +210,7 @@ func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeSta
func (this *AuthorityNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(AuthorityNodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).

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 生成集群变更任务
@@ -142,6 +155,12 @@ func (this *DNSTaskDAO) DeleteDNSTask(tx *dbs.Tx, taskId int64) error {
return err
}
// DeleteAllDNSTasks 删除所有任务
func (this *DNSTaskDAO) DeleteAllDNSTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// UpdateDNSTaskError 设置任务错误
func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error {
if taskId <= 0 {
@@ -156,10 +175,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
@@ -168,6 +201,27 @@ func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64) error {
return this.Save(tx, op)
}
// GenerateVersion 生成最新的版本号
func (this *DNSTaskDAO) GenerateVersion() int64 {
return time.Now().UnixNano()
}
// UpdateClusterDNSTasksDone 设置所有集群任务完成
func (this *DNSTaskDAO) UpdateClusterDNSTasksDone(tx *dbs.Tx, clusterId int64, maxVersion int64) error {
if clusterId <= 0 || maxVersion <= 0 {
return nil
}
return this.Query(tx).
Attr("clusterId", clusterId).
Attr("isOk", false).
Lte("version", maxVersion).
Set("isDone", true).
Set("isOk", true).
Set("error", "").
UpdateQuickly()
}
// DeleteDNSTasksWithClusterId 删除集群相关任务
func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error {
if clusterId <= 0 {

View File

@@ -1,17 +1,28 @@
package dns
package dns_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
"time"
)
func TestDNSTaskDAO_CreateDNSTask(t *testing.T) {
dbs.NotifyReady()
err := SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType")
err := dns.SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType")
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestDNSTaskDAO_UpdateClusterDNSTasksDone(t *testing.T) {
var dao = dns.NewDNSTaskDAO()
var tx *dbs.Tx
err := dao.UpdateClusterDNSTasksDone(tx, 46, time.Now().UnixNano())
if err != nil {
t.Fatal(err)
}
}

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

@@ -96,7 +96,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
}
// CreateCachePolicy 创建缓存策略
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
var op = NewHTTPCachePolicyOperator()
op.State = HTTPCachePolicyStateEnabled
op.IsOn = isOn
@@ -105,7 +105,6 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
if len(capacityJSON) > 0 {
op.Capacity = capacityJSON
}
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON
}
@@ -184,7 +183,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
return 0, err
}
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
if err != nil {
return 0, err
}
@@ -192,7 +191,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
}
// UpdateCachePolicy 修改缓存策略
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error {
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
@@ -205,7 +204,6 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
if len(capacityJSON) > 0 {
op.Capacity = capacityJSON
}
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON
}
@@ -256,8 +254,6 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
config.Capacity = capacityConfig
}
config.MaxKeys = types.Int64(policy.MaxKeys)
// max size
if IsNotNull(policy.MaxSize) {
maxSizeConfig := &shared.SizeCapacity{}

View File

@@ -33,7 +33,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedHTTPCacheTaskDAO.Clean(nil, 30) // 只保留N天
err := SharedHTTPCacheTaskDAO.CleanDefaultDays(nil, 30) // 只保留N天
if err != nil {
remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error())
}
@@ -228,8 +228,8 @@ func (this *HTTPCacheTaskDAO) CheckUserTask(tx *dbs.Tx, userId int64, taskId int
return nil
}
// Clean 清理以往的任务
func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
// CleanDays 清理N天以前的任务
func (this *HTTPCacheTaskDAO) CleanDays(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
@@ -248,6 +248,23 @@ func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
return err
}
// CleanDefaultDays 清除任务
func (this *HTTPCacheTaskDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.HTTPCacheTask.Clean.Days > 0 {
defaultDays = databaseConfig.HTTPCacheTask.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 30
}
return this.CleanDays(tx, defaultDays)
}
// NotifyChange 发送通知
func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error {
// TODO

View File

@@ -11,7 +11,7 @@ import (
func TestHTTPCacheTaskDAO_Clean(t *testing.T) {
dbs.NotifyReady()
err := models.SharedHTTPCacheTaskDAO.Clean(nil, 30)
err := models.SharedHTTPCacheTaskDAO.CleanDays(nil, 30)
if err != nil {
t.Fatal(err)
}

View File

@@ -132,7 +132,7 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
op.Outbound = outboundJSON
}
if userId <= 0 && serverGroupId <=0 && serverId <= 0 {
if userId <= 0 && serverGroupId <= 0 && serverId <= 0 {
// synFlood
var synFloodConfig = firewallconfigs.DefaultSYNFloodConfig()
synFloodJSON, err := json.Marshal(synFloodConfig)
@@ -611,6 +611,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyServerId(tx *dbs.Tx, poli
// FindFirewallPolicyIdsWithServerId 查找服务独立关联的策略IDs
func (this *HTTPFirewallPolicyDAO) FindFirewallPolicyIdsWithServerId(tx *dbs.Tx, serverId int64) ([]int64, error) {
if serverId <= 0 {
return nil, nil
}
var result = []int64{}
ones, err := this.Query(tx).
Attr("serverId", serverId).

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

@@ -124,8 +124,9 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
}
// CreateRewriteRule 创建规则
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, userId int64, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
var op = NewHTTPRewriteRuleOperator()
op.UserId = userId
op.State = HTTPRewriteRuleStateEnabled
op.IsOn = isOn
@@ -172,6 +173,34 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
return this.NotifyUpdate(tx, rewriteRuleId)
}
func (this *HTTPRewriteRuleDAO) CheckUserRewriteRule(tx *dbs.Tx, userId int64, rewriteRuleId int64) error {
if rewriteRuleId <= 0 {
return ErrNotFound
}
exists, err := this.Query(tx).
Pk(rewriteRuleId).
Attr("userId", userId).
Exist()
if err != nil {
return err
}
if !exists {
return ErrNotFound
}
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)
if err != nil {
return err
}
if webId <= 0 {
return ErrNotFound
}
return SharedHTTPWebDAO.CheckUserWeb(tx, userId, webId)
}
// NotifyUpdate 通知更新
func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)

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,139 @@ 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
if this.shouldCompose(isLocationOrGroup, forNode, compressionConfig.IsPrior, compressionConfig.IsOn) {
config.Compression = compressionConfig
// 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
}
// 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.Gzip = gzipConfig
}
}
// brotli
if compression.BrotliRef != nil && compression.BrotliRef.Id > 0 {
brotliConfig, err := SharedHTTPBrotliPolicyDAO.ComposeBrotliConfig(tx, compression.BrotliRef.Id)
if err != nil {
return nil, err
}
compression.Brotli = brotliConfig
// Optimization
if IsNotNull(web.Optimization) {
var optimizationConfig = serverconfigs.NewHTTPPageOptimizationConfig()
err = json.Unmarshal(web.Optimization, optimizationConfig)
if err != nil {
return nil, err
}
// deflate
if compression.DeflateRef != nil && compression.DeflateRef.Id > 0 {
deflateConfig, err := SharedHTTPDeflatePolicyDAO.ComposeDeflateConfig(tx, compression.DeflateRef.Id)
if err != nil {
return nil, err
}
compression.Deflate = deflateConfig
if this.shouldCompose(isLocationOrGroup, forNode, optimizationConfig.IsPrior, true) {
config.Optimization = optimizationConfig
}
}
// 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 +252,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 +325,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 +335,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 +387,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 +399,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 +431,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 +455,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 +467,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 +478,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 +505,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 +541,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 {
@@ -504,7 +562,20 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
if len(rootJSON) > 0 {
op.Root = JSONBytes(rootJSON)
}
err := this.Save(tx, op)
// 设置默认的remote-addr
// set default remote-addr config
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
IsOn: true,
Value: "${rawRemoteAddr}",
}
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
if err != nil {
return 0, err
}
op.RemoteAddr = remoteAddrConfigJSON
err = this.Save(tx, op)
if err != nil {
return 0, err
}
@@ -528,14 +599,42 @@ func (this *HTTPWebDAO) UpdateWeb(tx *dbs.Tx, webId int64, rootJSON []byte) erro
}
// UpdateWebCompression 修改压缩配置
func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig []byte) error {
func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig *serverconfigs.HTTPCompressionConfig) error {
if webId <= 0 {
return errors.New("invalid webId")
}
compressionJSON, err := json.Marshal(compressionConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator()
op.Id = webId
op.Compression = JSONBytes(compressionConfig)
err := this.Save(tx, op)
op.Compression = compressionJSON
err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
// UpdateWebOptimization 修改页面优化配置
func (this *HTTPWebDAO) UpdateWebOptimization(tx *dbs.Tx, webId int64, optimizationConfig *serverconfigs.HTTPPageOptimizationConfig) error {
if webId <= 0 {
return errors.New("invalid webId")
}
optimizationJSON, err := json.Marshal(optimizationConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator()
op.Id = webId
op.Optimization = optimizationJSON
err = this.Save(tx, op)
if err != nil {
return err
}
@@ -1110,8 +1209,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 +1449,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

@@ -2,6 +2,47 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPWebField_Id dbs.FieldName = "id" // ID
HTTPWebField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPWebField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPWebField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPWebField_UserId dbs.FieldName = "userId" // 用户ID
HTTPWebField_State dbs.FieldName = "state" // 状态
HTTPWebField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPWebField_Root dbs.FieldName = "root" // 根目录
HTTPWebField_Charset dbs.FieldName = "charset" // 字符集
HTTPWebField_Shutdown dbs.FieldName = "shutdown" // 临时关闭页面配置
HTTPWebField_Pages dbs.FieldName = "pages" // 特殊页面
HTTPWebField_RedirectToHttps dbs.FieldName = "redirectToHttps" // 跳转到HTTPS设置
HTTPWebField_Indexes dbs.FieldName = "indexes" // 首页文件列表
HTTPWebField_MaxRequestBodySize dbs.FieldName = "maxRequestBodySize" // 最大允许的请求内容尺寸
HTTPWebField_RequestHeader dbs.FieldName = "requestHeader" // 请求Header配置
HTTPWebField_ResponseHeader dbs.FieldName = "responseHeader" // 响应Header配置
HTTPWebField_AccessLog dbs.FieldName = "accessLog" // 访问日志配置
HTTPWebField_Stat dbs.FieldName = "stat" // 统计配置
HTTPWebField_Gzip dbs.FieldName = "gzip" // Gzip配置v0.3.2弃用)
HTTPWebField_Compression dbs.FieldName = "compression" // 压缩配置
HTTPWebField_Cache dbs.FieldName = "cache" // 缓存配置
HTTPWebField_Firewall dbs.FieldName = "firewall" // 防火墙设置
HTTPWebField_Locations dbs.FieldName = "locations" // 路由规则配置
HTTPWebField_Websocket dbs.FieldName = "websocket" // Websocket设置
HTTPWebField_RewriteRules dbs.FieldName = "rewriteRules" // 重写规则配置
HTTPWebField_HostRedirects dbs.FieldName = "hostRedirects" // 域名跳转
HTTPWebField_Fastcgi dbs.FieldName = "fastcgi" // Fastcgi配置
HTTPWebField_Auth dbs.FieldName = "auth" // 认证策略配置
HTTPWebField_Webp dbs.FieldName = "webp" // WebP配置
HTTPWebField_RemoteAddr dbs.FieldName = "remoteAddr" // 客户端IP配置
HTTPWebField_MergeSlashes dbs.FieldName = "mergeSlashes" // 是否合并路径中的斜杠
HTTPWebField_RequestLimit dbs.FieldName = "requestLimit" // 请求限制
HTTPWebField_RequestScripts dbs.FieldName = "requestScripts" // 请求脚本
HTTPWebField_Uam dbs.FieldName = "uam" // UAM设置
HTTPWebField_Cc dbs.FieldName = "cc" // CC设置
HTTPWebField_Referers dbs.FieldName = "referers" // 防盗链设置
HTTPWebField_UserAgent dbs.FieldName = "userAgent" // UserAgent设置
HTTPWebField_Optimization dbs.FieldName = "optimization" // 页面优化配置
)
// HTTPWeb HTTP Web
type HTTPWeb struct {
Id uint32 `field:"id"` // ID
@@ -41,6 +82,7 @@ type HTTPWeb struct {
Cc dbs.JSON `field:"cc"` // CC设置
Referers dbs.JSON `field:"referers"` // 防盗链设置
UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置
Optimization dbs.JSON `field:"optimization"` // 页面优化配置
}
type HTTPWebOperator struct {
@@ -81,6 +123,7 @@ type HTTPWebOperator struct {
Cc any // CC设置
Referers any // 防盗链设置
UserAgent any // UserAgent设置
Optimization any // 页面优化配置
}
func NewHTTPWebOperator() *HTTPWebOperator {

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

@@ -14,6 +14,7 @@ import (
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
"math"
"net"
"time"
)
@@ -75,13 +76,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 +103,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 +115,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 +131,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 +211,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 +252,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 +282,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 +310,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 +364,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 +390,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 +424,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,10 +487,23 @@ 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))
if net.ParseIP(keyword) != nil { // 是一个IP地址
query.Attr("ipFrom", keyword)
} else {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
}
}
if len(ip) > 0 {
query.Attr("ipFrom", ip)
@@ -499,10 +533,23 @@ 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))
if net.ParseIP(keyword) != nil { // 是一个IP地址
query.Attr("ipFrom", keyword)
} else {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
}
}
if len(ip) > 0 {
query.Attr("ipFrom", ip)
@@ -536,11 +583,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.ValueId),
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.ValueId),
Name: province.DisplayName(),
Codes: province.AllCodes(),
})
@@ -367,7 +369,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var cities = []*iplibrary.City{}
for _, city := range dbCities {
cities = append(cities, &iplibrary.City{
Id: city.Id,
Id: city.ValueId,
Name: city.DisplayName(),
Codes: city.AllCodes(),
})
@@ -382,7 +384,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var towns = []*iplibrary.Town{}
for _, town := range dbTowns {
towns = append(towns, &iplibrary.Town{
Id: town.Id,
Id: town.ValueId,
Name: town.DisplayName(),
Codes: town.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.ValueId),
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
}
@@ -438,35 +440,35 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countryMap = map[string]int64{} // countryName => countryId
for _, country := range dbCountries {
for _, code := range country.AllCodes() {
countryMap[code] = int64(country.Id)
countryMap[code] = int64(country.ValueId)
}
}
var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
for _, province := range dbProvinces {
for _, code := range province.AllCodes() {
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.Id)
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.ValueId)
}
}
var cityMap = map[string]int64{} // provinceId_cityName => cityId
for _, city := range dbCities {
for _, code := range city.AllCodes() {
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.Id)
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.ValueId)
}
}
var townMap = map[string]int64{} // cityId_townName => townId
for _, town := range dbTowns {
for _, code := range town.AllCodes() {
townMap[types.String(town.CityId)+"_"+code] = int64(town.Id)
townMap[types.String(town.CityId)+"_"+code] = int64(town.ValueId)
}
}
var providerMap = map[string]int64{} // providerName => providerId
for _, provider := range dbProviders {
for _, code := range provider.AllCodes() {
providerMap[code] = int64(provider.Id)
providerMap[code] = int64(provider.ValueId)
}
}

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

@@ -1,9 +1,11 @@
package models
import (
"encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -36,7 +38,7 @@ func init() {
}
// CreateLog 创建管理员日志
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error {
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string, langMessageCode langs.MessageCode, langMessageArgs []any) error {
var op = NewLogOperator()
op.Level = level
op.Description = utils.LimitString(description, 1000)
@@ -53,6 +55,16 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
op.ProviderId = adminId
}
// i18n
op.LangMessageCode = langMessageCode
if len(langMessageArgs) > 0 {
langMessageArgsJSON, err := json.Marshal(langMessageArgs)
if err != nil {
return err
}
op.LangMessageArgs = langMessageArgsJSON
}
op.Day = timeutil.Format("Ymd")
op.Type = LogTypeAdmin
err := this.Save(tx, op)
@@ -60,11 +72,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 +88,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 +104,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 +120,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

@@ -1,34 +1,60 @@
package models
// 操作日志
import "github.com/iwind/TeaGo/dbs"
const (
LogField_Id dbs.FieldName = "id" // ID
LogField_Level dbs.FieldName = "level" // 级别
LogField_Description dbs.FieldName = "description" // 描述
LogField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
LogField_Action dbs.FieldName = "action" // 动作
LogField_UserId dbs.FieldName = "userId" // 用户ID
LogField_AdminId dbs.FieldName = "adminId" // 管理员ID
LogField_ProviderId dbs.FieldName = "providerId" // 供应商ID
LogField_Ip dbs.FieldName = "ip" // IP地址
LogField_Type dbs.FieldName = "type" // 类型admin, user
LogField_Day dbs.FieldName = "day" // 日期
LogField_BillId dbs.FieldName = "billId" // 账单ID
LogField_LangMessageCode dbs.FieldName = "langMessageCode" // 多语言消息代号
LogField_LangMessageArgs dbs.FieldName = "langMessageArgs" // 多语言参数
LogField_Params dbs.FieldName = "params" // 关联对象参数
)
// Log 操作日志
type Log struct {
Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别
Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID
Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别
Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID
LangMessageCode string `field:"langMessageCode"` // 多语言消息代号
LangMessageArgs dbs.JSON `field:"langMessageArgs"` // 多语言参数
Params dbs.JSON `field:"params"` // 关联对象参数
}
type LogOperator struct {
Id interface{} // ID
Level interface{} // 级别
Description interface{} // 描述
CreatedAt interface{} // 创建时间
Action interface{} // 动作
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
ProviderId interface{} // 供应商ID
Ip interface{} // IP地址
Type interface{} // 类型admin, user
Day interface{} // 日期
BillId interface{} // 账单ID
Id any // ID
Level any // 级别
Description any // 描述
CreatedAt any // 创建时间
Action any // 动作
UserId any // 用户ID
AdminId any // 管理员ID
ProviderId any // 供应商ID
Ip any // IP地址
Type any // 类型admin, user
Day any // 日期
BillId any // 账单ID
LangMessageCode any // 多语言消息代号
LangMessageArgs any // 多语言参数
Params any // 关联对象参数
}
func NewLogOperator() *LogOperator {

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

@@ -207,6 +207,7 @@ func (this *MonitorNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSO
func (this *MonitorNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(MonitorNodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).

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

@@ -100,6 +100,7 @@ func (this *NodeClusterDAO) FindNodeClusterName(tx *dbs.Tx, clusterId int64) (st
// FindAllEnableClusters 查找所有可用的集群
func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) {
_, err = this.Query(tx).
Result(NodeClusterField_Id, NodeClusterField_Name, NodeClusterField_IsOn, NodeClusterField_HealthCheck, NodeClusterField_AutoRemoteStart, NodeClusterField_AutoRegister, NodeClusterField_CreatedAt, NodeClusterField_UniqueId, NodeClusterField_Secret).
State(NodeClusterStateEnabled).
Slice(&result).
Desc("isPinned").
@@ -175,7 +176,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// 全局服务配置
if globalServerConfig == nil {
globalServerConfig = serverconfigs.DefaultGlobalServerConfig()
globalServerConfig = serverconfigs.NewGlobalServerConfig()
}
globalServerConfigJSON, err := json.Marshal(globalServerConfig)
if err != nil {
@@ -262,19 +263,40 @@ func (this *NodeClusterDAO) CountAllEnabledClusters(tx *dbs.Tx, keyword string)
// ListEnabledClusters 列出单页集群
func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offset, size int64) (result []*NodeCluster, err error) {
query := this.Query(tx).
var query = this.Query(tx).
State(NodeClusterStateEnabled)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR dnsName like :keyword OR (dnsDomainId > 0 AND dnsDomainId IN (SELECT id FROM "+dns.SharedDNSDomainDAO.Table+" WHERE name LIKE :keyword AND state=1)))").
Param("keyword", dbutils.QuoteLike(keyword))
}
_, err = query.
Result(
NodeClusterField_Id,
NodeClusterField_Name,
NodeClusterField_IsOn,
NodeClusterField_IsPinned,
NodeClusterField_InstallDir,
NodeClusterField_HttpFirewallPolicyId,
NodeClusterField_AdminId,
NodeClusterField_IsOn,
NodeClusterField_IsAD,
NodeClusterField_UserId,
NodeClusterField_DnsName,
NodeClusterField_DnsDomainId,
NodeClusterField_Dns,
NodeClusterField_CreatedAt,
NodeClusterField_UniqueId,
NodeClusterField_Secret,
NodeClusterField_GrantId,
NodeClusterField_TimeZone,
).
Offset(offset).
Limit(size).
Slice(&result).
Desc("isPinned").
DescPk().
FindAll()
return
}
@@ -625,10 +647,10 @@ func (this *NodeClusterDAO) FindClusterTOAConfig(tx *dbs.Tx, clusterId int64, ca
return nil, err
}
if !IsNotNull([]byte(toa)) {
return nodeconfigs.DefaultTOAConfig(), nil
return nodeconfigs.NewTOAConfig(), nil
}
config := &nodeconfigs.TOAConfig{}
var config = nodeconfigs.NewTOAConfig()
err = json.Unmarshal([]byte(toa), config)
if err != nil {
return nil, err
@@ -653,7 +675,7 @@ func (this *NodeClusterDAO) UpdateClusterTOA(tx *dbs.Tx, clusterId int64, toaJSO
if err != nil {
return err
}
return this.NotifyUpdate(tx, clusterId)
return this.NotifyTOAUpdate(tx, clusterId)
}
// CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量
@@ -996,7 +1018,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", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables").
Find()
if err != nil || cluster == nil {
return nil, err
@@ -1077,7 +1099,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 +1114,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 {
@@ -1113,11 +1135,12 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return nil, err
}
var policy = nodeconfigs.NewUAMPolicy()
if IsNull(uamJSON) {
return nodeconfigs.DefaultUAMPolicy, nil
return policy, nil
}
var policy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(uamJSON, policy)
if err != nil {
return nil, err
@@ -1125,6 +1148,205 @@ 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
}
// UpdateClusterHTTP3Policy 修改HTTP3策略设置
func (this *NodeClusterDAO) UpdateClusterHTTP3Policy(tx *dbs.Tx, clusterId int64, http3Policy *nodeconfigs.HTTP3Policy) error {
if http3Policy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("http3", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTP3Update(tx, clusterId)
}
http3PolicyJSON, err := json.Marshal(http3Policy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("http3", http3PolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTP3Update(tx, clusterId)
}
// FindClusterHTTP3Policy 查询HTTP3策略设置
func (this *NodeClusterDAO) FindClusterHTTP3Policy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTP3Policy, error) {
var cacheKey = this.Table + ":FindClusterHTTP3Policy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTP3Policy), nil
}
}
http3PolicyJSON, err := this.Query(tx).
Pk(clusterId).
Result("http3").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(http3PolicyJSON) {
return nodeconfigs.NewHTTP3Policy(), nil
}
var policy = nodeconfigs.NewHTTP3Policy()
err = json.Unmarshal(http3PolicyJSON, 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).
@@ -1174,7 +1396,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
return nil, err
}
var config = serverconfigs.DefaultGlobalServerConfig()
var config = serverconfigs.NewGlobalServerConfig()
if IsNull(configJSON) {
return config, nil
}
@@ -1190,7 +1412,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
// UpdateClusterGlobalServerConfig 修改全局服务配置
func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error {
if config == nil {
config = serverconfigs.DefaultGlobalServerConfig()
config = serverconfigs.NewGlobalServerConfig()
}
configJSON, err := json.Marshal(config)
if err != nil {
@@ -1212,12 +1434,33 @@ 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)
}
// NotifyHTTP3Update 通知HTTP3更新
func (this *NodeClusterDAO) NotifyHTTP3Update(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTP3PolicyChanged)
}
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
}
// NotifyTOAUpdate 通知TOA变化
func (this *NodeClusterDAO) NotifyTOAUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeTOAChanged)
}
// NotifyDNSUpdate 通知DNS更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {
err := dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
if err != nil {
return err
}
return nil
return dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
}

View File

@@ -2,6 +2,49 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
NodeClusterField_Id dbs.FieldName = "id" // ID
NodeClusterField_AdminId dbs.FieldName = "adminId" // 管理员ID
NodeClusterField_UserId dbs.FieldName = "userId" // 用户ID
NodeClusterField_IsOn dbs.FieldName = "isOn" // 是否启用
NodeClusterField_Name dbs.FieldName = "name" // 名称
NodeClusterField_UseAllAPINodes dbs.FieldName = "useAllAPINodes" // 是否使用所有API节点
NodeClusterField_ApiNodes dbs.FieldName = "apiNodes" // 使用的API节点
NodeClusterField_InstallDir dbs.FieldName = "installDir" // 安装目录
NodeClusterField_Order dbs.FieldName = "order" // 排序
NodeClusterField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
NodeClusterField_GrantId dbs.FieldName = "grantId" // 默认认证方式
NodeClusterField_SshParams dbs.FieldName = "sshParams" // SSH默认参数
NodeClusterField_State dbs.FieldName = "state" // 状态
NodeClusterField_AutoRegister dbs.FieldName = "autoRegister" // 是否开启自动注册
NodeClusterField_UniqueId dbs.FieldName = "uniqueId" // 唯一ID
NodeClusterField_Secret dbs.FieldName = "secret" // 密钥
NodeClusterField_HealthCheck dbs.FieldName = "healthCheck" // 健康检查
NodeClusterField_DnsName dbs.FieldName = "dnsName" // DNS名称
NodeClusterField_DnsDomainId dbs.FieldName = "dnsDomainId" // 域名ID
NodeClusterField_Dns dbs.FieldName = "dns" // DNS配置
NodeClusterField_Toa dbs.FieldName = "toa" // TOA配置
NodeClusterField_CachePolicyId dbs.FieldName = "cachePolicyId" // 缓存策略ID
NodeClusterField_HttpFirewallPolicyId dbs.FieldName = "httpFirewallPolicyId" // WAF策略ID
NodeClusterField_AccessLog dbs.FieldName = "accessLog" // 访问日志设置
NodeClusterField_SystemServices dbs.FieldName = "systemServices" // 系统服务设置
NodeClusterField_TimeZone dbs.FieldName = "timeZone" // 时区
NodeClusterField_NodeMaxThreads dbs.FieldName = "nodeMaxThreads" // 节点最大线程数
NodeClusterField_DdosProtection dbs.FieldName = "ddosProtection" // DDoS防护设置
NodeClusterField_AutoOpenPorts dbs.FieldName = "autoOpenPorts" // 是否自动尝试开放端口
NodeClusterField_IsPinned dbs.FieldName = "isPinned" // 是否置顶
NodeClusterField_Webp dbs.FieldName = "webp" // WebP设置
NodeClusterField_Uam dbs.FieldName = "uam" // UAM设置
NodeClusterField_Clock dbs.FieldName = "clock" // 时钟配置
NodeClusterField_GlobalServerConfig dbs.FieldName = "globalServerConfig" // 全局服务配置
NodeClusterField_AutoRemoteStart dbs.FieldName = "autoRemoteStart" // 自动远程启动
NodeClusterField_AutoInstallNftables dbs.FieldName = "autoInstallNftables" // 自动安装nftables
NodeClusterField_IsAD dbs.FieldName = "isAD" // 是否为高防集群
NodeClusterField_HttpPages dbs.FieldName = "httpPages" // 自定义页面设置
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
)
// NodeCluster 节点集群
type NodeCluster struct {
Id uint32 `field:"id"` // ID
@@ -41,6 +84,9 @@ 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设置
Http3 dbs.JSON `field:"http3"` // HTTP3设置
}
type NodeClusterOperator struct {
@@ -81,6 +127,9 @@ type NodeClusterOperator struct {
AutoRemoteStart any // 自动远程启动
AutoInstallNftables any // 自动安装nftables
IsAD any // 是否为高防集群
HttpPages any // 自定义页面设置
Cc any // CC设置
Http3 any // HTTP3设置
}
func NewNodeClusterOperator() *NodeClusterOperator {

View File

@@ -60,7 +60,7 @@ func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
// DecodeGlobalServerConfig 解析全局服务配置
func (this *NodeCluster) DecodeGlobalServerConfig() *serverconfigs.GlobalServerConfig {
var config = serverconfigs.DefaultGlobalServerConfig()
var config = serverconfigs.NewGlobalServerConfig()
if IsNotNull(this.GlobalServerConfig) {
err := json.Unmarshal(this.GlobalServerConfig, config)
if err != nil {

View File

@@ -295,6 +295,7 @@ func (this *NodeDAO) CountAllEnabledNodes(tx *dbs.Tx) (int64, error) {
func (this *NodeDAO) CountAllEnabledOfflineNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=:clusterState)").
Param("clusterState", NodeClusterStateEnabled).
Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)").
@@ -356,7 +357,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 +436,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 +841,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 +903,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 +963,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 +987,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 +1000,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 +1045,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 +1086,12 @@ 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.HTTP3Policies = map[int64]*nodeconfigs.HTTP3Policy{}
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
var cachePolicyIds = []int64{}
var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
@@ -1079,12 +1131,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// 缓存策略
var httpCachePolicyId = int64(nodeCluster.CachePolicyId)
if httpCachePolicyId > 0 {
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
if err != nil {
return nil, err
}
if cachePolicy != nil {
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
if !lists.ContainsInt64(cachePolicyIds, httpCachePolicyId) {
cachePolicyIds = append(cachePolicyIds, httpCachePolicyId)
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
if err != nil {
return nil, err
}
if cachePolicy != nil {
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
}
}
}
@@ -1125,7 +1180,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// UAM
if IsNotNull(nodeCluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{}
var uamPolicy = nodeconfigs.NewUAMPolicy()
err = json.Unmarshal(nodeCluster.Uam, uamPolicy)
if err != nil {
return nil, err
@@ -1133,6 +1188,59 @@ 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
}
// HTTP3 Policy
if IsNotNull(nodeCluster.Http3) {
var http3Policy = nodeconfigs.NewHTTP3Policy()
err = json.Unmarshal(nodeCluster.Http3, http3Policy)
if err != nil {
return nil, err
}
config.HTTP3Policies[clusterId] = http3Policy
}
// 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 +1457,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).
@@ -1383,6 +1491,7 @@ func (this *NodeDAO) FindAllNotInstalledNodesWithClusterId(tx *dbs.Tx, clusterId
func (this *NodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId int64, os string, arch string, version string) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Attr("clusterId", clusterId).
Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os").
@@ -1416,6 +1525,7 @@ func (this *NodeDAO) FindAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId
func (this *NodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=1)").
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
@@ -1485,7 +1595,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 +1614,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 +1640,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,12 @@ const (
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
// NS相关
@@ -228,6 +234,12 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
return err
}
// DeleteAllNodeTasks 删除所有节点相关任务
func (this *NodeTaskDAO) DeleteAllNodeTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// FindDoingNodeTasks 查询一个节点的所有任务
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) {
if nodeId <= 0 {
@@ -236,6 +248,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 +307,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"
@@ -22,7 +22,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedNodeTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天
err := SharedNodeTrafficDailyStatDAO.CleanDefaultDays(nil, 32) // 只保留N天
if err != nil {
remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
}
@@ -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,11 +119,42 @@ func (this *NodeTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, role string, nod
return result, nil
}
// Clean 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
// 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
}
// CleanDays 清理历史数据
func (this *NodeTrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Lt("day", day).
Delete()
return err
}
func (this *NodeTrafficDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.NodeTrafficDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.NodeTrafficDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 32
}
return this.CleanDays(tx, defaultDays)
}

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

@@ -15,6 +15,7 @@ type NSCluster struct {
Tcp dbs.JSON `field:"tcp"` // TCP设置
Tls dbs.JSON `field:"tls"` // TLS设置
Udp dbs.JSON `field:"udp"` // UDP设置
Doh dbs.JSON `field:"doh"` // DoH设置
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
Hosts dbs.JSON `field:"hosts"` // DNS主机地址
Soa dbs.JSON `field:"soa"` // SOA配置
@@ -24,6 +25,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 {
@@ -38,6 +40,7 @@ type NSClusterOperator struct {
Tcp any // TCP设置
Tls any // TLS设置
Udp any // UDP设置
Doh any // DoH设置
DdosProtection any // DDoS防护设置
Hosts any // DNS主机地址
Soa any // SOA配置
@@ -47,6 +50,7 @@ type NSClusterOperator struct {
SoaSerial any // SOA序列号
Email any // 管理员邮箱
DetectAgents any // 是否监测Agents
CheckingPorts any // 自动检测端口
}
func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -93,6 +93,7 @@ func (this *NSNodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, cluste
return this.Query(tx).
State(NSNodeStateEnabled).
Attr("clusterId", clusterId).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os").
Where("JSON_EXTRACT(status, '$.arch')=:arch").
@@ -161,6 +162,7 @@ func (this *NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *no
func (this *NSNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(NSNodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNSClusterDAO.Table+" WHERE state=1)").
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").

View File

@@ -5,6 +5,7 @@ import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ossconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -91,7 +92,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
adminId int64,
userId int64,
name string,
addrJSON string,
addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string,
weight int32, isOn bool,
connTimeout *shared.TimeDuration,
@@ -102,7 +104,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef,
domains []string,
host string,
followPort bool) (originId int64, err error) {
followPort bool,
http2Enabled bool) (originId int64, err error) {
var op = NewOriginOperator()
op.AdminId = adminId
op.UserId = userId
@@ -141,7 +144,18 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.MaxIdleConns = 0
}
op.Addr = addrJSON
if len(addrJSON) > 0 {
op.Addr = addrJSON
}
if ossConfig != nil {
ossConfigJSON, err := json.Marshal(ossConfig)
if err != nil {
return 0, err
}
op.Oss = ossConfigJSON
}
op.Description = description
if weight < 0 {
weight = 0
@@ -169,6 +183,7 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.Host = host
op.FollowPort = followPort
op.Http2Enabled = http2Enabled
op.State = OriginStateEnabled
err = this.Save(tx, op)
@@ -182,7 +197,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
originId int64,
name string,
addrJSON string,
addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string,
weight int32,
isOn bool,
@@ -194,14 +210,25 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef,
domains []string,
host string,
followPort bool) error {
followPort bool,
http2Enabled bool) error {
if originId <= 0 {
return errors.New("invalid originId")
}
var op = NewOriginOperator()
op.Id = originId
op.Name = name
op.Addr = addrJSON
if ossConfig != nil {
ossConfigJSON, err := json.Marshal(ossConfig)
if err != nil {
return err
}
op.Oss = ossConfigJSON
}
op.Description = description
if weight < 0 {
weight = 0
@@ -266,6 +293,7 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
op.Host = host
op.FollowPort = followPort
op.Http2Enabled = http2Enabled
err := this.Save(tx, op)
if err != nil {
@@ -275,8 +303,67 @@ 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.Http2Enabled = origin.Http2Enabled
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()
}
@@ -309,8 +396,10 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
RequestHost: origin.Host,
Domains: origin.DecodeDomains(),
FollowPort: origin.FollowPort,
HTTP2Enabled: origin.Http2Enabled,
}
// addr
if IsNotNull(origin.Addr) {
var addr = &serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(origin.Addr, addr)
@@ -320,6 +409,16 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
config.Addr = addr
}
// oss
if IsNotNull(origin.Oss) {
var ossConfig = ossconfigs.NewOSSConfig()
err = json.Unmarshal(origin.Oss, ossConfig)
if err != nil {
return nil, err
}
config.OSS = ossConfig
}
if IsNotNull(origin.ConnTimeout) {
var connTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.ConnTimeout, &connTimeout)
@@ -403,7 +502,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

@@ -11,6 +11,7 @@ type Origin struct {
Name string `field:"name"` // 名称
Version uint32 `field:"version"` // 版本
Addr dbs.JSON `field:"addr"` // 地址
Oss dbs.JSON `field:"oss"` // OSS配置
Description string `field:"description"` // 描述
Code string `field:"code"` // 代号
Weight uint32 `field:"weight"` // 权重
@@ -31,36 +32,39 @@ type Origin struct {
Domains dbs.JSON `field:"domains"` // 所属域名
FollowPort bool `field:"followPort"` // 端口跟随
State uint8 `field:"state"` // 状态
Http2Enabled bool `field:"http2Enabled"` // 是否支持HTTP/2
}
type OriginOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
IsOn interface{} // 是否启用
Name interface{} // 名称
Version interface{} // 版本
Addr interface{} // 地址
Description interface{} // 描述
Code interface{} // 代号
Weight interface{} // 权重
ConnTimeout interface{} // 连接超时
ReadTimeout interface{} // 超时
IdleTimeout interface{} // 空闲连接超时
MaxFails interface{} // 最多失败次数
MaxConns interface{} // 最大并发连接
MaxIdleConns interface{} // 最多空闲连接数
HttpRequestURI interface{} // 转发后的请求URI
HttpRequestHeader interface{} // 请求Header配置
HttpResponseHeader interface{} // 响应Header配置
Host interface{} // 自定义主机名
HealthCheck interface{} // 健康检查设置
Cert interface{} // 证书设置
Ftp interface{} // FTP相关设置
CreatedAt interface{} // 创建时间
Domains interface{} // 所属域名
FollowPort interface{} // 端口跟随
State interface{} // 状态
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 名称
Version any // 版本
Addr any // 地址
Oss any // OSS配置
Description any // 描述
Code any // 代号
Weight any // 权重
ConnTimeout any // 连接超时
ReadTimeout any // 超时
IdleTimeout any // 空闲连接超时
MaxFails any // 最多失败次
MaxConns any // 最大并发连接数
MaxIdleConns any // 最多空闲连接数
HttpRequestURI any // 转发后的请求URI
HttpRequestHeader any // 请求Header配置
HttpResponseHeader any // 响应Header配置
Host any // 自定义主机名
HealthCheck any // 健康检查设置
Cert any // 证书设置
Ftp any // FTP相关设置
CreatedAt any // 创建时间
Domains any // 所属域名
FollowPort any // 端口跟随
State any // 状态
Http2Enabled any // 是否支持HTTP/2
}
func NewOriginOperator() *OriginOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionCity 启用条目
func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCityStateEnabled).
Update()
return err
@@ -51,7 +51,7 @@ func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
// DisableRegionCity 禁用条目
func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCityStateDisabled).
Update()
return err
@@ -60,7 +60,7 @@ func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionCity 查找启用中的条目
func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionCity, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionCityStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionC
// FindRegionCityName 根据主键查找名称
func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -81,7 +81,7 @@ func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, er
func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionCityField_ValueId).
FindInt64Col(0)
}
@@ -93,7 +93,7 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
op.DataId = dataId
op.State = RegionCityStateEnabled
codes := []string{name}
var codes = []string{name}
codesJSON, err := json.Marshal(codes)
if err != nil {
return 0, err
@@ -103,7 +103,18 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var cityId = types.Int64(op.Id)
// value id
err = this.Query(tx).
Pk(cityId).
Set(RegionCityField_ValueId, cityId).
UpdateQuickly()
if err != nil {
return 0, err
}
return cityId, nil
}
// FindCityIdWithName 根据城市名查找城市ID
@@ -113,7 +124,7 @@ func (this *RegionCityDAO) FindCityIdWithName(tx *dbs.Tx, provinceId int64, city
Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))").
Param("cityName", cityName).
Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionCityField_ValueId).
FindInt64Col(0)
}
@@ -147,7 +158,7 @@ func (this *RegionCityDAO) UpdateCityCustom(tx *dbs.Tx, cityId int64, customName
}
return this.Query(tx).
Pk(cityId).
Attr(RegionCityField_ValueId, cityId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionCityField_Id dbs.FieldName = "id" // ID
RegionCityField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCityField_ProvinceId dbs.FieldName = "provinceId" // 省份ID
RegionCityField_Name dbs.FieldName = "name" // 名称
RegionCityField_Codes dbs.FieldName = "codes" // 代号
RegionCityField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCityField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCityField_State dbs.FieldName = "state" // 状态
RegionCityField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionCity 区域-城市
type RegionCity struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ProvinceId uint32 `field:"provinceId"` // 省份ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionCity struct {
}
type RegionCityOperator struct {
Id interface{} // ID
ProvinceId interface{} // 省份ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 实际ID
ProvinceId any // 省份ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionCityOperator() *RegionCityOperator {

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -20,10 +21,6 @@ const (
RegionCountryStateDisabled = 0 // 已禁用
)
const (
CountryChinaId = 1
)
var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
type RegionCountryDAO dbs.DAO
@@ -50,7 +47,7 @@ func init() {
// EnableRegionCountry 启用条目
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCountryStateEnabled).
Update()
return err
@@ -59,7 +56,7 @@ func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
// DisableRegionCountry 禁用条目
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCountryStateDisabled).
Update()
return err
@@ -68,7 +65,7 @@ func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
// FindEnabledRegionCountry 查找启用中的条目
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionCountryStateEnabled).
Find()
if result == nil {
@@ -88,7 +85,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
}
name, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
if err != nil {
@@ -105,7 +102,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionCountryField_ValueId).
FindInt64Col(0)
}
@@ -115,7 +112,7 @@ func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName stri
Where("(name=:countryName OR JSON_CONTAINS(codes, :countryNameJSON) OR customName=:countryName OR JSON_CONTAINS(customCodes, :countryNameJSON))").
Param("countryName", countryName).
Param("countryNameJSON", strconv.Quote(countryName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionCountryField_ValueId).
FindInt64Col(0)
}
@@ -145,16 +142,61 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var countryId = types.Int64(op.Id)
err = this.Query(tx).
Pk(countryId).
Set(RegionCountryField_ValueId, countryId).
UpdateQuickly()
if err != nil {
return 0, err
}
return countryId, nil
}
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家并按拼音排序
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
_, err = this.Query(tx).
ones, err := this.Query(tx).
State(RegionCountryStateEnabled).
Slice(&result).
Asc("pinyin").
Asc("JSON_EXTRACT(pinyin, '$[0]')").
FindAll()
if err != nil {
return nil, err
}
// resort China special regions
var chinaRegionMap = map[int64]*RegionCountry{} // countryId => *RegionCountry
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
chinaRegionMap[valueId] = country
}
}
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if valueId == regionconfigs.RegionChinaId {
result = append(result, country)
// add hk, tw, mo, mainland ...
for _, subRegionId := range regionconfigs.FindAllGreaterChinaSubRegionIds() {
subRegion, ok := chinaRegionMap[subRegionId]
if ok {
result = append(result, subRegion)
}
}
continue
}
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
continue
}
result = append(result, country)
}
return
}
@@ -163,7 +205,7 @@ func (this *RegionCountryDAO) FindAllCountries(tx *dbs.Tx) (result []*RegionCoun
_, err = this.Query(tx).
State(RegionCountryStateEnabled).
Slice(&result).
AscPk().
Asc(RegionCountryField_ValueId).
FindAll()
return
}
@@ -185,7 +227,7 @@ func (this *RegionCountryDAO) UpdateCountryCustom(tx *dbs.Tx, countryId int64, c
}()
return this.Query(tx).
Pk(countryId).
Attr("valueId", countryId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,25 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionCountryField_Id dbs.FieldName = "id" // ID
RegionCountryField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCountryField_ValueCode dbs.FieldName = "valueCode" // 值代号
RegionCountryField_Name dbs.FieldName = "name" // 名称
RegionCountryField_Codes dbs.FieldName = "codes" // 代号
RegionCountryField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCountryField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCountryField_State dbs.FieldName = "state" // 状态
RegionCountryField_DataId dbs.FieldName = "dataId" // 原始数据ID
RegionCountryField_Pinyin dbs.FieldName = "pinyin" // 拼音
RegionCountryField_IsCommon dbs.FieldName = "isCommon" // 是否常用
)
// RegionCountry 区域-国家/地区
type RegionCountry struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ValueCode string `field:"valueCode"` // 值代号
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称
@@ -12,17 +28,21 @@ type RegionCountry struct {
State uint8 `field:"state"` // 状态
DataId string `field:"dataId"` // 原始数据ID
Pinyin dbs.JSON `field:"pinyin"` // 拼音
IsCommon bool `field:"isCommon"` // 是否常用
}
type RegionCountryOperator struct {
Id interface{} // ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Pinyin interface{} // 拼音
Id any // ID
ValueId any // 实际ID
ValueCode any // 代号
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
Pinyin any // 拼音
IsCommon any // 是否常用
}
func NewRegionCountryOperator() *RegionCountryOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionProvider 启用条目
func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProviderStateEnabled).
Update()
return err
@@ -50,7 +50,7 @@ func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error
// DisableRegionProvider 禁用条目
func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProviderStateDisabled).
Update()
return err
@@ -59,7 +59,7 @@ func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) erro
// FindEnabledRegionProvider 查找启用中的条目
func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (*RegionProvider, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionProviderStateEnabled).
Find()
if result == nil {
@@ -71,7 +71,7 @@ func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (
// FindRegionProviderName 根据主键查找名称
func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -82,7 +82,7 @@ func (this *RegionProviderDAO) FindProviderIdWithName(tx *dbs.Tx, providerName s
Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))").
Param("providerName", providerName).
Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionProviderField_ValueId).
FindInt64Col(0)
}
@@ -96,7 +96,20 @@ func (this *RegionProviderDAO) CreateProvider(tx *dbs.Tx, name string) (int64, e
return 0, err
}
op.Codes = codesJSON
return this.SaveInt64(tx, op)
providerId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(providerId).
Set(RegionProviderField_ValueId, providerId).
UpdateQuickly()
if err != nil {
return 0, err
}
return providerId, nil
}
// FindAllEnabledProviders 查找所有服务商
@@ -119,7 +132,7 @@ func (this *RegionProviderDAO) UpdateProviderCustom(tx *dbs.Tx, providerId int64
}
return this.Query(tx).
Pk(providerId).
Attr("valueId", providerId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,20 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionProviderField_Id dbs.FieldName = "id" // ID
RegionProviderField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProviderField_Name dbs.FieldName = "name" // 名称
RegionProviderField_Codes dbs.FieldName = "codes" // 代号
RegionProviderField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProviderField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProviderField_State dbs.FieldName = "state" // 状态
)
// RegionProvider 区域-运营商
type RegionProvider struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称
@@ -13,12 +24,13 @@ type RegionProvider struct {
}
type RegionProviderOperator struct {
Id interface{} // ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
Id any // ID
ValueId any // 实际ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
}
func NewRegionProviderOperator() *RegionProviderOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionProvince 启用条目
func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProvinceStateEnabled).
Update()
return err
@@ -51,7 +51,7 @@ func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error
// DisableRegionProvince 禁用条目
func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProvinceStateDisabled).
Update()
return err
@@ -60,7 +60,7 @@ func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error
// FindEnabledRegionProvince 查找启用中的条目
func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionProvinceStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (
// FindRegionProvinceName 根据主键查找名称
func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -81,7 +81,7 @@ func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (str
func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionProvinceField_ValueId).
FindInt64Col(0)
}
@@ -92,7 +92,7 @@ func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int6
Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))").
Param("provinceName", provinceName).
Param("provinceNameJSON", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionProvinceField_ValueId).
FindInt64Col(0)
}
@@ -104,7 +104,7 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
op.DataId = dataId
op.State = RegionProvinceStateEnabled
codes := []string{name}
var codes = []string{name}
codesJSON, err := json.Marshal(codes)
if err != nil {
return 0, err
@@ -114,7 +114,17 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var provinceId = types.Int64(op.Id)
err = this.Query(tx).
Pk(provinceId).
Set(RegionProvinceField_ValueId, provinceId).
UpdateQuickly()
if err != nil {
return 0, err
}
return provinceId, nil
}
// FindAllEnabledProvincesWithCountryId 查找某个国家/地区的所有省份
@@ -122,7 +132,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
_, err = this.Query(tx).
State(RegionProvinceStateEnabled).
Attr("countryId", countryId).
Asc().
Asc(RegionProvinceField_ValueId).
Slice(&result).
FindAll()
return
@@ -132,7 +142,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().
Asc(RegionProvinceField_ValueId).
Slice(&result).
FindAll()
return
@@ -149,7 +159,7 @@ func (this *RegionProvinceDAO) UpdateProvinceCustom(tx *dbs.Tx, provinceId int64
}
return this.Query(tx).
Pk(provinceId).
Attr("valueId", provinceId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionProvinceField_Id dbs.FieldName = "id" // ID
RegionProvinceField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProvinceField_CountryId dbs.FieldName = "countryId" // 国家ID
RegionProvinceField_Name dbs.FieldName = "name" // 名称
RegionProvinceField_Codes dbs.FieldName = "codes" // 代号
RegionProvinceField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProvinceField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProvinceField_State dbs.FieldName = "state" // 状态
RegionProvinceField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionProvince 区域-省份
type RegionProvince struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
CountryId uint32 `field:"countryId"` // 国家ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionProvince struct {
}
type RegionProvinceOperator struct {
Id interface{} // ID
CountryId interface{} // 国家ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 实际ID
CountryId any // 国家ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionProvinceOperator() *RegionProvinceOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionTown 启用条目
func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionTownStateEnabled).
Update()
return err
@@ -50,7 +50,7 @@ func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
// DisableRegionTown 禁用条目
func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionTownStateDisabled).
Update()
return err
@@ -59,7 +59,7 @@ func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionTown 查找启用中的区县
func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionTown, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionTownStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionT
func (this *RegionTownDAO) FindAllRegionTowns(tx *dbs.Tx) (result []*RegionTown, err error) {
_, err = this.Query(tx).
State(RegionTownStateEnabled).
AscPk().
Asc(RegionTownField_ValueId).
Slice(&result).
FindAll()
return
@@ -83,7 +83,7 @@ func (this *RegionTownDAO) FindAllRegionTownsWithCityId(tx *dbs.Tx, cityId int64
_, err = this.Query(tx).
State(RegionTownStateEnabled).
Attr("cityId", cityId).
AscPk().
Asc(RegionTownField_ValueId).
Slice(&result).
FindAll()
return
@@ -96,14 +96,14 @@ func (this *RegionTownDAO) FindTownIdWithName(tx *dbs.Tx, cityId int64, townName
Where("(name=:townName OR customName=:townName OR JSON_CONTAINS(codes, :townNameJSON) OR JSON_CONTAINS(customCodes, :townNameJSON))").
Param("townName", townName).
Param("townNameJSON", strconv.Quote(townName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionTownField_ValueId).
FindInt64Col(0)
}
// FindRegionTownName 根据主键查找名称
func (this *RegionTownDAO) FindRegionTownName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -118,7 +118,7 @@ func (this *RegionTownDAO) UpdateTownCustom(tx *dbs.Tx, townId int64, customName
return err
}
return this.Query(tx).
Pk(townId).
Attr("valueId", townId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()
@@ -176,5 +176,18 @@ func (this *RegionTownDAO) CreateTown(tx *dbs.Tx, cityId int64, townName string)
op.Codes = codes
op.State = RegionTownStateEnabled
return this.SaveInt64(tx, op)
townId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(townId).
Set(RegionTownField_ValueId, townId).
UpdateQuickly()
if err != nil {
return 0, err
}
return townId, nil
}

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionTownField_Id dbs.FieldName = "id" // ID
RegionTownField_ValueId dbs.FieldName = "valueId" // 真实ID
RegionTownField_CityId dbs.FieldName = "cityId" // 城市ID
RegionTownField_Name dbs.FieldName = "name" // 名称
RegionTownField_Codes dbs.FieldName = "codes" // 代号
RegionTownField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionTownField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionTownField_State dbs.FieldName = "state" // 状态
RegionTownField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionTown 区域-省份
type RegionTown struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 真实ID
CityId uint32 `field:"cityId"` // 城市ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionTown struct {
}
type RegionTownOperator struct {
Id interface{} // ID
CityId interface{} // 城市ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 真实ID
CityId any // 城市ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionTownOperator() *RegionTownOperator {

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"
@@ -33,7 +34,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedServerBandwidthStatDAO.Clean(nil)
err := SharedServerBandwidthStatDAO.CleanDefaultDays(nil, 100)
if err != nil {
remotelogs.Error("SharedServerBandwidthStatDAO", "clean expired data failed: "+err.Error())
}
@@ -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,9 +560,194 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serve
return this.fixServerStat(one.(*ServerBandwidthStat), useAvg), nil
}
// Clean 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据
// 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
}
// CleanDays 清理过期数据
func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx).
Table(table).
@@ -552,6 +757,22 @@ func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
})
}
func (this *ServerBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerBandwidthStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerBandwidthStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 100
}
return this.CleanDays(tx, defaultDays)
}
// 批量执行
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
@@ -619,3 +840,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)
}
@@ -69,11 +72,11 @@ func TestServerBandwidthStatDAO_FindAllServerStatsWithDay(t *testing.T) {
}
}
func TestServerBandwidthStatDAO_Clean(t *testing.T) {
func TestServerBandwidthStatDAO_CleanDays(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
var before = time.Now()
err := dao.Clean(tx)
err := dao.CleanDays(tx, 100)
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

@@ -16,6 +16,7 @@ import (
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"sort"
"strings"
"time"
)
@@ -28,7 +29,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
err := SharedServerDailyStatDAO.CleanDefaultDays(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
if err != nil {
logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
}
@@ -61,19 +62,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 +201,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 +240,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 +329,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 +469,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 +482,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)
@@ -508,7 +514,8 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day", "timeFrom", "MIN(timeTo) AS timeTo").
Attr("serverId", serverId).
Attr("day", day).
Group("day").Group("timeFrom", dbs.QueryOrderDesc)
Group("day").
Group("timeFrom")
if len(timeFrom) > 0 {
query.Gte("timeFrom", timeFrom)
@@ -525,6 +532,11 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
return nil, err
}
// sort results
sort.Slice(result, func(i, j int) bool {
return result[i].TimeFrom < result[j].TimeFrom
})
return
}
@@ -640,7 +652,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 +663,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 +679,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",
})
}
}
@@ -731,11 +749,27 @@ func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee floa
UpdateQuickly()
}
// Clean 清理历史数据
func (this *ServerDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
// CleanDays 清理历史数据
func (this *ServerDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Lt("day", day).
Delete()
return err
}
func (this *ServerDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 60
}
return this.CleanDays(tx, defaultDays)
}

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,14 +99,47 @@ 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 {
t.Fatal(err)
}
for _, stat := range stats {
t.Log(stat.TimeFrom, stat.TimeTo, stat.Bytes)
t.Log(stat.Day, stat.TimeFrom, stat.TimeTo, stat.Bytes)
}
}

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
@@ -340,6 +354,9 @@ func (this *ServerDAO) UpdateServerBasic(tx *dbs.Tx, serverId int64, name string
// UpdateServerGroupIds 修改服务所在分组
func (this *ServerDAO) UpdateServerGroupIds(tx *dbs.Tx, serverId int64, groupIds []int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
if groupIds == nil {
groupIds = []int64{}
}
@@ -376,6 +393,10 @@ func (this *ServerDAO) UpdateUserServerBasic(tx *dbs.Tx, serverId int64, name st
// UpdateServerIsOn 修复服务是否启用
func (this *ServerDAO) UpdateServerIsOn(tx *dbs.Tx, serverId int64, isOn bool) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
_, err := this.Query(tx).
Pk(serverId).
Set("isOn", isOn).
@@ -783,9 +804,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 +862,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)
@@ -878,6 +903,22 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), bandwidthBytes, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "requestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "requestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
default:
query.DescPk()
}
@@ -888,6 +929,8 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
for _, server := range result {
if len(server.BandwidthTime) > 0 && !lists.ContainsString(times, server.BandwidthTime) {
server.BandwidthBytes = 0
server.CountRequests = 0
server.CountAttackRequests = 0
}
}
@@ -1009,12 +1052,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 +1077,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 +1143,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 +1156,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 +1179,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 +1192,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 +1215,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 +1227,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 +1253,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 +1488,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 +1496,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 +1619,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 +1647,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)).
@@ -2108,6 +2178,10 @@ func (this *ServerDAO) FindFirstHTTPOrHTTPSPortWithClusterId(tx *dbs.Tx, cluster
// NotifyServerPortsUpdate 通知服务端口变化
func (this *ServerDAO) NotifyServerPortsUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
one, err := this.Query(tx).
Pk(serverId).
Result("tcp", "tls", "udp", "http", "https").
@@ -2435,6 +2509,10 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
// IncreaseServerTotalTraffic 增加服务的总流量
func (this *ServerDAO) IncreaseServerTotalTraffic(tx *dbs.Tx, serverId int64, bytes int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
var gb = float64(bytes) / (1 << 30)
var day = timeutil.Format("Ymd")
var month = timeutil.Format("Ym")
@@ -2494,6 +2572,10 @@ func (this *ServerDAO) UpdateServersClusterIdWithPlanId(tx *dbs.Tx, planId int64
// UpdateServerUserPlanId 设置服务所属套餐
func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPlanId int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
oldClusterId, err := this.Query(tx).
Pk(serverId).
Result("clusterId").
@@ -2601,6 +2683,10 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
// FindServerLastUserPlanIdAndUserId 查找最后使用的套餐
func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId int64) (userPlanId int64, userId int64, err error) {
if serverId <= 0 {
return 0, 0, errors.New("serverId should not be smaller than 0")
}
one, err := this.Query(tx).
Pk(serverId).
Result("lastUserPlanId", "userId").
@@ -2614,6 +2700,10 @@ func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId in
// UpdateServerUAM 开启UAM
func (this *ServerDAO) UpdateServerUAM(tx *dbs.Tx, serverId int64, uamConfig *serverconfigs.UAMConfig) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
if uamConfig == nil {
return nil
}
@@ -2665,7 +2755,7 @@ func (this *ServerDAO) FindUserServerClusterIds(tx *dbs.Tx, userId int64) ([]int
// UpdateServerBandwidth 更新服务带宽
// fullTime YYYYMMDDHHII
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64) error {
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64, countRequests int64, countAttackRequests int64) error {
if serverId <= 0 {
return nil
}
@@ -2686,13 +2776,19 @@ func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTim
Pk(serverId).
Set("bandwidthTime", fullTime).
Set("bandwidthBytes", bandwidthBytes).
Set("countRequests", countRequests).
Set("countAttackRequests", countAttackRequests).
UpdateQuickly()
} else {
return this.Query(tx).
Pk(serverId).
Set("bandwidthTime", fullTime).
Set("bandwidthBytes", dbs.SQL("bandwidthBytes+:bytes")).
Set("countRequests", dbs.SQL("countRequests+:countRequests")).
Set("countAttackRequests", dbs.SQL("countAttackRequests+:countAttackRequests")).
Param("bytes", bandwidthBytes).
Param("countRequests", countRequests).
Param("countAttackRequests", countAttackRequests).
UpdateQuickly()
}
}
@@ -2763,8 +2859,34 @@ 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 {
if serverId <= 0 {
return nil
}
// 创建任务
clusterId, err := this.FindServerClusterId(tx, serverId)
if err != nil {
@@ -2778,6 +2900,9 @@ func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
// NotifyClusterUpdate 同步指定的集群
func (this *ServerDAO) NotifyClusterUpdate(tx *dbs.Tx, clusterId, serverId int64) error {
if serverId <= 0 {
return nil
}
if clusterId <= 0 {
return nil
}
@@ -2786,6 +2911,10 @@ func (this *ServerDAO) NotifyClusterUpdate(tx *dbs.Tx, clusterId, serverId int64
// NotifyDNSUpdate 通知当前集群DNS更新
func (this *ServerDAO) NotifyDNSUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
clusterId, err := this.Query(tx).
Pk(serverId).
Result("clusterId").
@@ -2811,6 +2940,10 @@ func (this *ServerDAO) NotifyDNSUpdate(tx *dbs.Tx, serverId int64) error {
// NotifyClusterDNSUpdate 通知某个集群中的DNS更新
func (this *ServerDAO) NotifyClusterDNSUpdate(tx *dbs.Tx, clusterId int64, serverId int64) error {
if serverId <= 0 {
return nil
}
dnsInfo, err := SharedNodeClusterDAO.FindClusterDNSInfo(tx, clusterId, nil)
if err != nil {
return err
@@ -2826,6 +2959,10 @@ func (this *ServerDAO) NotifyClusterDNSUpdate(tx *dbs.Tx, clusterId int64, serve
// NotifyDisable 通知禁用
func (this *ServerDAO) NotifyDisable(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
// 禁用缓存策略相关的内容
policyIds, err := SharedHTTPFirewallPolicyDAO.FindFirewallPolicyIdsWithServerId(tx, serverId)
if err != nil {

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")
@@ -229,7 +229,7 @@ func TestServerDAO_FindEnabledServerWithDomain(t *testing.T) {
for _, domain := range []string{"a", "a.com", "teaos.cn", "www.teaos.cn", "cdn.teaos.cn", "google.com"} {
var before = time.Now()
server, err := dao.FindEnabledServerWithDomain(tx, domain)
server, err := dao.FindEnabledServerWithDomain(tx, 0, domain)
var costMs = time.Since(before).Seconds() * 1000
if err != nil {
t.Fatal(err)
@@ -326,12 +326,22 @@ func TestServerDAO_FindBool(t *testing.T) {
func TestServerDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerDAO()
var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, timeutil.FormatTime("YmdHi", time.Now().Unix()/300*300), 1024)
err := dao.UpdateServerBandwidth(tx, 1, timeutil.FormatTime("YmdHi", time.Now().Unix()/300*300), 1024, 1, 0)
if err != nil {
t.Fatal(err)
}
}
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

@@ -2,6 +2,57 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
ServerField_Id dbs.FieldName = "id" // ID
ServerField_IsOn dbs.FieldName = "isOn" // 是否启用
ServerField_UserId dbs.FieldName = "userId" // 用户ID
ServerField_AdminId dbs.FieldName = "adminId" // 管理员ID
ServerField_Type dbs.FieldName = "type" // 服务类型
ServerField_Name dbs.FieldName = "name" // 名称
ServerField_Description dbs.FieldName = "description" // 描述
ServerField_PlainServerNames dbs.FieldName = "plainServerNames" // 扁平化域名列表
ServerField_ServerNames dbs.FieldName = "serverNames" // 域名列表
ServerField_AuditingAt dbs.FieldName = "auditingAt" // 审核提交时间
ServerField_AuditingServerNames dbs.FieldName = "auditingServerNames" // 审核中的域名
ServerField_IsAuditing dbs.FieldName = "isAuditing" // 是否正在审核
ServerField_AuditingResult dbs.FieldName = "auditingResult" // 审核结果
ServerField_Http dbs.FieldName = "http" // HTTP配置
ServerField_Https dbs.FieldName = "https" // HTTPS配置
ServerField_Tcp dbs.FieldName = "tcp" // TCP配置
ServerField_Tls dbs.FieldName = "tls" // TLS配置
ServerField_Unix dbs.FieldName = "unix" // Unix配置
ServerField_Udp dbs.FieldName = "udp" // UDP配置
ServerField_WebId dbs.FieldName = "webId" // WEB配置
ServerField_ReverseProxy dbs.FieldName = "reverseProxy" // 反向代理配置
ServerField_GroupIds dbs.FieldName = "groupIds" // 分组ID列表
ServerField_Config dbs.FieldName = "config" // 服务配置,自动生成
ServerField_ConfigMd5 dbs.FieldName = "configMd5" // Md5
ServerField_ClusterId dbs.FieldName = "clusterId" // 集群ID
ServerField_IncludeNodes dbs.FieldName = "includeNodes" // 部署条件
ServerField_ExcludeNodes dbs.FieldName = "excludeNodes" // 节点排除条件
ServerField_Version dbs.FieldName = "version" // 版本号
ServerField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
ServerField_State dbs.FieldName = "state" // 状态
ServerField_DnsName dbs.FieldName = "dnsName" // DNS名称
ServerField_TcpPorts dbs.FieldName = "tcpPorts" // 所包含TCP端口
ServerField_UdpPorts dbs.FieldName = "udpPorts" // 所包含UDP端口
ServerField_SupportCNAME dbs.FieldName = "supportCNAME" // 允许CNAME不在域名名单
ServerField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
ServerField_TrafficDay dbs.FieldName = "trafficDay" // YYYYMMDD
ServerField_TrafficMonth dbs.FieldName = "trafficMonth" // YYYYMM
ServerField_TotalDailyTraffic dbs.FieldName = "totalDailyTraffic" // 日流量
ServerField_TotalMonthlyTraffic dbs.FieldName = "totalMonthlyTraffic" // 月流量
ServerField_TrafficLimitStatus dbs.FieldName = "trafficLimitStatus" // 流量限制状态
ServerField_TotalTraffic dbs.FieldName = "totalTraffic" // 总流量
ServerField_UserPlanId dbs.FieldName = "userPlanId" // 所属套餐ID
ServerField_LastUserPlanId dbs.FieldName = "lastUserPlanId" // 上一次使用的套餐
ServerField_Uam dbs.FieldName = "uam" // UAM设置
ServerField_BandwidthTime dbs.FieldName = "bandwidthTime" // 带宽更新时间YYYYMMDDHHII
ServerField_BandwidthBytes dbs.FieldName = "bandwidthBytes" // 最近带宽峰值
ServerField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 最近攻击请求数
ServerField_CountRequests dbs.FieldName = "countRequests" // 最近总请求数
)
// Server 服务
type Server struct {
Id uint32 `field:"id"` // ID
@@ -50,6 +101,8 @@ type Server struct {
Uam dbs.JSON `field:"uam"` // UAM设置
BandwidthTime string `field:"bandwidthTime"` // 带宽更新时间YYYYMMDDHHII
BandwidthBytes uint64 `field:"bandwidthBytes"` // 最近带宽峰值
CountAttackRequests uint64 `field:"countAttackRequests"` // 最近攻击请求数
CountRequests uint64 `field:"countRequests"` // 最近总请求数
}
type ServerOperator struct {
@@ -99,6 +152,8 @@ type ServerOperator struct {
Uam any // UAM设置
BandwidthTime any // 带宽更新时间YYYYMMDDHHII
BandwidthBytes any // 最近带宽峰值
CountAttackRequests any // 最近攻击请求数
CountRequests any // 最近总请求数
}
func NewServerOperator() *ServerOperator {

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
}

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