Compare commits

...

134 Commits

Author SHA1 Message Date
刘祥超
6a9045ba44 提交SQL 2022-07-18 09:13:16 +08:00
刘祥超
bc7ee19962 优化代码 2022-07-17 17:08:28 +08:00
刘祥超
2484cd4ae6 可以通过ID查找服务 2022-07-17 11:43:23 +08:00
刘祥超
57b8a96c6d 增加用户身份认证相关接口 2022-07-17 11:00:14 +08:00
刘祥超
6c8ab7cb94 集群DNS设置增加允许通过CNAME访问网站服务选项 2022-07-14 09:49:09 +08:00
刘祥超
b2c2bd247b 更新SQL 2022-07-12 14:22:20 +08:00
刘祥超
29d9e6db81 域名解析支持DNS.COM(商业版) 2022-07-11 11:51:49 +08:00
刘祥超
24fcb48c75 删除节点的时候同时也删除相关的运行日志 2022-07-07 20:31:12 +08:00
刘祥超
4911198fe7 安全设置中增加禁止搜索引擎、禁止爬虫、允许访问的域名等选项 2022-07-07 19:58:50 +08:00
刘祥超
c2af796992 服务看板增加峰值带宽数据 2022-07-07 17:11:49 +08:00
刘祥超
51c8572e53 用户界面设置中增加流量、带宽相关设置 2022-07-07 12:40:05 +08:00
刘祥超
c15cc6d75c 增加按用户统计带宽/修改其他相关代码 2022-07-07 09:18:08 +08:00
刘祥超
c0a99a4ba3 升级Go版本为1.18 2022-07-06 16:13:52 +08:00
刘祥超
62e26bed5a 增加服务带宽统计 2022-07-05 20:08:58 +08:00
刘祥超
9e68a2915c 增加UAM(5秒盾)集群设置 2022-07-03 22:10:46 +08:00
刘祥超
5b809fda1f 反向代理设置中增加移除回源主机名端口功能 2022-06-30 12:12:41 +08:00
刘祥超
88b782940a 提交SQL 2022-06-29 22:17:32 +08:00
刘祥超
85c596644d 实现源站端口跟随功能 2022-06-29 21:55:57 +08:00
刘祥超
ffa2d884bd 移除386、mips等不常用节点安装文件 2022-06-29 17:11:13 +08:00
刘祥超
813ed18610 优化编译脚本 2022-06-29 16:57:46 +08:00
刘祥超
564b11eae7 优化编译脚本 2022-06-29 14:52:11 +08:00
刘祥超
d2af0307b9 将DNS版本改为0.2.4 2022-06-28 20:31:59 +08:00
刘祥超
4fa6b03238 对于小内存(不大于2G),缩短服务统计导入数据库的时间 2022-06-25 20:57:03 +08:00
刘祥超
4bda78aa8c 限制节点自动升级时的速度和并发数 2022-06-25 20:36:31 +08:00
刘祥超
6002cc96d9 增加修改服务所在分组API 2022-06-25 19:21:46 +08:00
刘祥超
56c09f5be7 指标数据写入改成队列执行 2022-06-22 21:51:44 +08:00
刘祥超
e1fb8e4c74 删除某个IP时更新版本 2022-06-22 18:59:27 +08:00
刘祥超
14f055ce7c fix typo 2022-06-22 14:00:56 +08:00
刘祥超
7b7f2b0a00 修改版本号为v0.4.9 2022-06-20 16:00:27 +08:00
刘祥超
75662586fa 修改相关节点版本 2022-06-20 09:34:40 +08:00
刘祥超
c024331fa0 增加统计服务某日、某月流量API 2022-06-18 14:26:43 +08:00
刘祥超
b01ea79c5c 升级IP名单权限判断逻辑 2022-06-15 19:22:33 +08:00
刘祥超
d59f80b3ec 优化缓存任务Key状态增加执行中状态 2022-06-15 15:18:18 +08:00
刘祥超
b87e48c1f9 城市API增加省份信息 2022-06-14 17:37:42 +08:00
刘祥超
0e7a7f168f 访问日志查询增加requestPath:/hello、proto:HTTP/1.1、scheme:http等语法 2022-06-12 20:30:28 +08:00
刘祥超
2bbc09d3af 优化syslog提示、优化其他代码 2022-06-08 19:55:06 +08:00
刘祥超
97b50fab28 删除EdgePlus 2022-06-08 15:14:30 +08:00
刘祥超
83c867cb65 API节点启动失败后记录相关问题和处理建议 2022-06-08 15:13:24 +08:00
刘祥超
3c4b7ca57b 节点状态中增加时间戳字段 2022-06-06 19:39:08 +08:00
刘祥超
a2f98d2f25 可以设置用户每天执行缓存任务的额度 2022-06-05 21:15:28 +08:00
刘祥超
71677a8638 增加刷新、预热缓存任务管理 2022-06-05 17:13:56 +08:00
刘祥超
95a2187f95 优化API/修改用户集群不影响套餐服务 2022-05-25 11:44:18 +08:00
刘祥超
86bec813bf fix typo 2022-05-22 11:48:31 +08:00
刘祥超
0d7bd6f04e 增加LICENSE和README 2022-05-22 11:36:54 +08:00
刘祥超
d7117209b2 删除不过期IP时不立即删除,以等待节点完成同步 2022-05-21 22:06:04 +08:00
刘祥超
7a340ac68b 新创建WAF时增加默认选项 2022-05-21 18:58:03 +08:00
刘祥超
353b1b4ad1 WAF策略中增加验证码相关定制设置 2022-05-20 22:07:23 +08:00
刘祥超
fdac8beb40 健康检查增加是否记录访问日志选项 2022-05-19 17:14:32 +08:00
刘祥超
f098723a41 实现基础的DDoS防护 2022-05-18 21:02:53 +08:00
刘祥超
6ded627903 增加通过IP删除IP名单中IP参数 2022-05-10 15:11:48 +08:00
刘祥超
ed2d5ee5cc fix typo 2022-05-08 19:33:17 +08:00
刘祥超
c677368482 集群节点列表可以使用“未分组”筛选 2022-05-08 19:33:10 +08:00
刘祥超
51ccd614a7 忽略部分MySQL 1213错误 2022-05-08 00:24:22 +08:00
刘祥超
9be7f61b8c 阿里云DNS增加区域ID 2022-05-07 21:00:07 +08:00
刘祥超
14ad97c937 DNS服务商增加厂家筛选 2022-05-07 20:41:53 +08:00
刘祥超
94609d8ef4 EdgeUser版本升级为0.3.4 2022-05-05 18:56:35 +08:00
刘祥超
e34e38bcb2 Update sql.go 2022-05-04 20:35:38 +08:00
刘祥超
b10d9fe842 路由规则可以单独设置UAM(仅企业版可用) 2022-05-04 20:32:34 +08:00
刘祥超
992e725378 节点增加DNS解析库类型设置 2022-05-04 16:40:34 +08:00
刘祥超
346de7ca7a 版本修改为0.4.8 2022-04-25 11:11:43 +08:00
刘祥超
b212e124c2 统计看板中合并相同Key的指标数据 2022-04-24 15:24:40 +08:00
刘祥超
ee2781fe65 优化代码 2022-04-23 13:26:15 +08:00
刘祥超
89c1edc9ee 多个API节点时选择一个作为主节点/优化任务相关代码 2022-04-23 12:32:30 +08:00
刘祥超
773f3e1a7e 修复无法使用倒序分表查询日志的问题 2022-04-22 22:23:07 +08:00
刘祥超
e6f6f4dcc2 集群概要信息中增加系统服务状态 2022-04-22 22:04:29 +08:00
刘祥超
174946aa4d 修复集群健康检查无法自动上下线IP地址的Bug 2022-04-22 21:53:38 +08:00
刘祥超
93c594a785 更新SQL 2022-04-22 17:16:19 +08:00
刘祥超
2aea527dff 访问日志策略增加只记录WAF相关访问日志选项 2022-04-22 17:13:59 +08:00
刘祥超
fa30015ca5 增加WAF策略日志设置 2022-04-21 20:00:56 +08:00
刘祥超
d06c8cebf5 IP列表增加名单类型筛选 2022-04-21 15:09:18 +08:00
刘祥超
e4ef2e8253 WAF策略增加日志配置(暂未开放) /修复通过IP可能无法查询到访问日志的Bug 2022-04-21 09:41:04 +08:00
刘祥超
665aa06cc7 优化代码 2022-04-19 19:48:37 +08:00
刘祥超
88dfda82d6 Linux下自动添加端口到Firewalld 2022-04-19 19:35:50 +08:00
刘祥超
243463df83 优化代码 2022-04-19 12:58:00 +08:00
刘祥超
2dc1bfcb55 创建和修改证书的时候检查时间 2022-04-19 11:09:42 +08:00
刘祥超
e6f7cafe7e 当修改集群主域名和DNS子域名时,自动删除旧的相关域名 2022-04-18 21:00:40 +08:00
刘祥超
26fe3558f4 如果服务变更集群前后域名ID一致,则不执行删除操作 2022-04-18 18:35:57 +08:00
刘祥超
ea09ef3d91 服务切换集群后,直接删除老的域名记录 2022-04-18 18:21:29 +08:00
刘祥超
c4ca2521ee 单个服务切换集群时可以选择是否保留配置 2022-04-18 17:18:00 +08:00
刘祥超
db5cdd2957 修复没有日志数据库时无法进行分区查询的Bug 2022-04-17 16:50:38 +08:00
刘祥超
0f483b98ec 删除一处调试信息 2022-04-17 16:24:27 +08:00
刘祥超
0fe51abeb1 访问日志可以使用分表查询 2022-04-17 16:18:53 +08:00
刘祥超
db6b7f57bb 修复看板中统计数据可能不显示的问题 2022-04-16 22:22:05 +08:00
刘祥超
663ead19e4 优化节点排序 2022-04-16 14:45:54 +08:00
刘祥超
bc8adb663a 服务列表增加下行带宽 2022-04-15 12:14:59 +08:00
刘祥超
08b5dd7531 判断节点数量时增加集群状态检查 2022-04-14 22:00:47 +08:00
刘祥超
8177f3d7e4 可以通过groupId=-1查询到未分组的服务 2022-04-14 16:58:21 +08:00
刘祥超
bb5252caf6 edgeServers增加plainServerNames字段 2022-04-14 16:44:00 +08:00
刘祥超
bd4a47d2a1 服务列表中分组信息中增加UserId字段 2022-04-13 15:01:45 +08:00
刘祥超
300be4e936 预估同时间流量的时候刻度改为10分钟 2022-04-10 21:57:26 +08:00
刘祥超
c9dbfb79a7 按天统计流量接口可以预估某日同时间流量 2022-04-10 21:25:24 +08:00
刘祥超
589ae124f1 修复访问日志可能显示重复的问题 2022-04-10 18:21:52 +08:00
刘祥超
d72b440406 修改DNS版本为0.2.2 2022-04-10 16:02:21 +08:00
刘祥超
63e4e7cf9f 优化本地日志 2022-04-10 15:57:36 +08:00
刘祥超
ad416dddec 增加两个数据库相关调试命令 2022-04-08 15:09:33 +08:00
刘祥超
4e18129c6c 更新TeaGo 2022-04-08 14:57:20 +08:00
刘祥超
c03d9f1880 优化数据库相关代码 2022-04-08 14:15:45 +08:00
刘祥超
fe448e6556 增加当日统计接口 2022-04-07 19:46:50 +08:00
刘祥超
adcb33fce4 优化节点列表 2022-04-07 18:31:38 +08:00
刘祥超
e58c3774b6 优化代码 2022-04-05 19:32:35 +08:00
刘祥超
cd7e01c2f0 商业版支持L2节点 2022-04-04 12:08:08 +08:00
刘祥超
d884777a55 增加单元测试 2022-04-02 11:52:42 +08:00
刘祥超
c48aba1c99 更新TeaGo 2022-04-02 11:52:11 +08:00
刘祥超
8cc0faf1d7 集群可以单独设置WebP策略 2022-04-01 16:42:23 +08:00
刘祥超
9851b1a146 集群可以设置WebP策略 2022-04-01 16:18:54 +08:00
刘祥超
36162c603d 看板:只有指标数据不为空时才缓存 2022-04-01 10:00:10 +08:00
刘祥超
cc2782584e 自定义页面支持用户操作 2022-03-31 15:30:04 +08:00
刘祥超
1c1e82ee38 指标统计数据分表 2022-03-30 15:35:42 +08:00
刘祥超
4b3a9cedfa 可以用域名搜索DNS账号 2022-03-30 11:15:38 +08:00
刘祥超
e9497ee65d DNSPod支持国际站 2022-03-30 10:56:22 +08:00
刘祥超
29fae55dc6 IP列表可以使用级别筛选 2022-03-30 09:39:43 +08:00
刘祥超
54fdf3b762 支持DNSPod国际版(需要测试) 2022-03-30 09:12:42 +08:00
刘祥超
f609008984 商业版增加UAM功能 2022-03-29 21:24:31 +08:00
刘祥超
f9b6838dc6 写入指标统计数据时忽略MySQL 1213错误 2022-03-29 20:01:49 +08:00
刘祥超
6d2ecb9af3 对统计指标进行分表 2022-03-28 16:25:16 +08:00
刘祥超
7c4a01137b 数据库管理中列出更多可手动清理的数据表 2022-03-28 11:19:50 +08:00
刘祥超
418c15f79f 数据库管理中列出更多可手动清理的数据表 2022-03-28 11:12:49 +08:00
刘祥超
d13176b8a5 可以自行设定指标数据保留时间 2022-03-28 09:37:28 +08:00
刘祥超
b2752ddd5a 优化看板打开速度 2022-03-27 16:39:54 +08:00
刘祥超
7aea2fd48c 访问日志关键词支持完整的URL/优化Like语句 2022-03-27 12:22:47 +08:00
刘祥超
803f11659c 优化代码 2022-03-26 22:04:16 +08:00
刘祥超
073926ff67 修改用户平台版本为0.3.3 2022-03-26 22:04:10 +08:00
刘祥超
65b4832c94 增加脚本相关表 2022-03-25 14:11:17 +08:00
刘祥超
5f793f1f76 IP找不到不再提示错误 2022-03-24 21:41:14 +08:00
刘祥超
0ce1df25bc 可以修复单页或者全部服务日志 2022-03-23 17:31:26 +08:00
刘祥超
06ad9cc63b 版本号改为0.4.7 2022-03-23 14:45:37 +08:00
刘祥超
57247d0f5b 修复访问日志可能无法写入当天数据表的Bug 2022-03-23 10:58:54 +08:00
刘祥超
813267c50f 修复访问日志表可能无法自动创建的Bug 2022-03-23 10:05:42 +08:00
刘祥超
b8078e73b2 更改版本为v0.4.6 2022-03-23 10:03:57 +08:00
刘祥超
f958c57984 优化代码 2022-03-22 22:11:32 +08:00
刘祥超
30bfbdc01e 优化代码 2022-03-22 21:45:07 +08:00
刘祥超
314362c24d 优化代码 2022-03-22 19:30:30 +08:00
刘祥超
8582715be7 字段中的blob和JSON类型映射为[]byte和dbs.JSON 2022-03-21 21:39:36 +08:00
刘祥超
74e585263c 升级TeaGo 2022-03-21 19:46:14 +08:00
411 changed files with 12238 additions and 3974 deletions

29
LICENSE Normal file
View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2020, LiuXiangChao
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
README.md Normal file
View File

@@ -0,0 +1 @@
GoEdge API节点源码

View File

@@ -1,76 +1,76 @@
#!/usr/bin/env bash #!/usr/bin/env bash
function build() { function build() {
ROOT=$(dirname $0) ROOT=$(dirname "$0")
NAME="edge-api" NAME="edge-api"
DIST=$ROOT/"../dist/${NAME}" DIST=$ROOT/"../dist/${NAME}"
OS=${1} OS=${1}
ARCH=${2} ARCH=${2}
TAG=${3} TAG=${3}
NODE_ARCHITECTS=("amd64" "386" "arm64" "mips64" "mips64le") NODE_ARCHITECTS=("amd64" "arm64")
if [ -z $OS ]; then if [ -z "$OS" ]; then
echo "usage: build.sh OS ARCH" echo "usage: build.sh OS ARCH"
exit exit
fi fi
if [ -z $ARCH ]; then if [ -z "$ARCH" ]; then
echo "usage: build.sh OS ARCH" echo "usage: build.sh OS ARCH"
exit exit
fi fi
if [ -z $TAG ]; then if [ -z "$TAG" ]; then
TAG="community" TAG="community"
fi fi
VERSION=$(lookup-version $ROOT/../internal/const/const.go) VERSION=$(lookup-version "$ROOT"/../internal/const/const.go)
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip" ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
# build edge-node # build edge-node
NodeVersion=$(lookup-version $ROOT"/../../EdgeNode/internal/const/const.go") NodeVersion=$(lookup-version "$ROOT""/../../EdgeNode/internal/const/const.go")
echo "building edge-node v${NodeVersion} ..." echo "building edge-node v${NodeVersion} ..."
EDGE_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeNode/build/build.sh" EDGE_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeNode/build/build.sh"
if [ ! -f $EDGE_NODE_BUILD_SCRIPT ]; then if [ ! -f "$EDGE_NODE_BUILD_SCRIPT" ]; then
echo "unable to find edge-node build script 'EdgeNode/build/build.sh'" echo "unable to find edge-node build script 'EdgeNode/build/build.sh'"
exit exit
fi fi
cd $ROOT"/../../EdgeNode/build" cd "$ROOT""/../../EdgeNode/build" || exit
echo "==============================" echo "=============================="
for arch in "${NODE_ARCHITECTS[@]}"; do for arch in "${NODE_ARCHITECTS[@]}"; do
if [ ! -f $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" ]; then if [ ! -f "$ROOT""/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" ]; then
./build.sh linux $arch $TAG ./build.sh linux "$arch" $TAG
else else
echo "use built node linux/$arch/v${NodeVersion}" echo "use built node linux/$arch/v${NodeVersion}"
fi fi
done done
echo "==============================" echo "=============================="
cd - cd - || exit
rm -f $ROOT/deploy/*.zip rm -f "$ROOT"/deploy/*.zip
for arch in "${NODE_ARCHITECTS[@]}"; do for arch in "${NODE_ARCHITECTS[@]}"; do
cp $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" $ROOT/deploy/edge-node-linux-${arch}-v${NodeVersion}.zip cp "$ROOT""/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" "$ROOT"/deploy/edge-node-linux-"${arch}"-v"${NodeVersion}".zip
done done
# build edge-dns # build edge-dns
if [ "$TAG" = "plus" ]; then if [ "$TAG" = "plus" ]; then
DNS_ROOT=$ROOT"/../../EdgeDNS" DNS_ROOT=$ROOT"/../../EdgeDNS"
if [ -d $DNS_ROOT ]; then if [ -d "$DNS_ROOT" ]; then
DNSNodeVersion=$(lookup-version $ROOT"/../../EdgeDNS/internal/const/const.go") DNSNodeVersion=$(lookup-version "$ROOT""/../../EdgeDNS/internal/const/const.go")
echo "building edge-dns ${DNSNodeVersion} ..." echo "building edge-dns ${DNSNodeVersion} ..."
EDGE_DNS_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeDNS/build/build.sh" EDGE_DNS_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeDNS/build/build.sh"
if [ ! -f $EDGE_DNS_NODE_BUILD_SCRIPT ]; then if [ ! -f "$EDGE_DNS_NODE_BUILD_SCRIPT" ]; then
echo "unable to find edge-dns build script 'EdgeDNS/build/build.sh'" echo "unable to find edge-dns build script 'EdgeDNS/build/build.sh'"
exit exit
fi fi
cd $ROOT"/../../EdgeDNS/build" cd "$ROOT""/../../EdgeDNS/build" || exit
echo "==============================" echo "=============================="
architects=("amd64") architects=("amd64" "arm64")
for arch in "${architects[@]}"; do for arch in "${architects[@]}"; do
./build.sh linux $arch $TAG ./build.sh linux "$arch" $TAG
done done
echo "==============================" echo "=============================="
cd - cd - || exit
for arch in "${architects[@]}"; do for arch in "${architects[@]}"; do
cp $ROOT"/../../EdgeDNS/dist/edge-dns-linux-${arch}-v${DNSNodeVersion}.zip" $ROOT/deploy/edge-dns-linux-${arch}-v${DNSNodeVersion}.zip cp "$ROOT""/../../EdgeDNS/dist/edge-dns-linux-${arch}-v${DNSNodeVersion}.zip" "$ROOT"/deploy/edge-dns-linux-"${arch}"-v"${DNSNodeVersion}".zip
done done
fi fi
fi fi
@@ -78,48 +78,48 @@ function build() {
# build sql # build sql
if [ $TAG = "plus" ]; then if [ $TAG = "plus" ]; then
echo "building sql ..." echo "building sql ..."
${ROOT}/sql.sh "${ROOT}"/sql.sh
fi fi
# copy files # copy files
echo "copying ..." echo "copying ..."
if [ ! -d $DIST ]; then if [ ! -d "$DIST" ]; then
mkdir $DIST mkdir "$DIST"
mkdir $DIST/bin mkdir "$DIST"/bin
mkdir $DIST/configs mkdir "$DIST"/configs
mkdir $DIST/logs mkdir "$DIST"/logs
fi fi
cp $ROOT/configs/api.template.yaml $DIST/configs/ cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/
cp $ROOT/configs/db.template.yaml $DIST/configs/ cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/
cp -R $ROOT/deploy $DIST/ cp -R "$ROOT"/deploy "$DIST/"
rm -f $dist/deploy/.gitignore rm -f "$DIST"/deploy/.gitignore
cp -R $ROOT/installers $DIST/ cp -R "$ROOT"/installers "$DIST"/
cp -R $ROOT/resources $DIST/ cp -R "$ROOT"/resources "$DIST"/
rm -f $DIST/resources/ipdata/ip2region/global_region.csv rm -f "$DIST"/resources/ipdata/ip2region/global_region.csv
rm -f $DIST/resources/ipdata/ip2region/ip.merge.txt rm -f "$DIST"/resources/ipdata/ip2region/ip.merge.txt
# building edge installer # building edge installer
echo "building node installer ..." echo "building node installer ..."
architects=("amd64" "386" "arm64") architects=("amd64" "arm64")
for arch in "${architects[@]}"; do for arch in "${architects[@]}"; do
# TODO support arm, mips ... # TODO support arm, mips ...
env GOOS=linux GOARCH=${arch} go build -tags $TAG --ldflags="-s -w" -o $ROOT/installers/edge-installer-helper-linux-${arch} $ROOT/../cmd/installer-helper/main.go env GOOS=linux GOARCH="${arch}" go build -trimpath -tags $TAG --ldflags="-s -w" -o "$ROOT"/installers/edge-installer-helper-linux-"${arch}" "$ROOT"/../cmd/installer-helper/main.go
done done
# building edge dns installer # building edge dns installer
echo "building dns node installer ..." echo "building dns node installer ..."
architects=("amd64" "386" "arm64") architects=("amd64" "arm64")
for arch in "${architects[@]}"; do for arch in "${architects[@]}"; do
# TODO support arm, mips ... # TODO support arm, mips ...
env GOOS=linux GOARCH=${arch} go build -tags $TAG --ldflags="-s -w" -o $ROOT/installers/edge-installer-dns-helper-linux-${arch} $ROOT/../cmd/installer-dns-helper/main.go env GOOS=linux GOARCH="${arch}" go build -trimpath -tags $TAG --ldflags="-s -w" -o "$ROOT"/installers/edge-installer-dns-helper-linux-"${arch}" "$ROOT"/../cmd/installer-dns-helper/main.go
done done
# building api node # building api node
env GOOS=$OS GOARCH=$ARCH go build -tags $TAG --ldflags="-s -w" -o $DIST/bin/edge-api $ROOT/../cmd/edge-api/main.go env GOOS="$OS" GOARCH="$ARCH" go build -trimpath -tags $TAG --ldflags="-s -w" -o "$DIST"/bin/edge-api "$ROOT"/../cmd/edge-api/main.go
# delete hidden files # delete hidden files
find $DIST -name ".DS_Store" -delete find "$DIST" -name ".DS_Store" -delete
find $DIST -name ".gitignore" -delete find "$DIST" -name ".gitignore" -delete
echo "zip files" echo "zip files"
cd "${DIST}/../" || exit cd "${DIST}/../" || exit
@@ -135,15 +135,15 @@ function build() {
function lookup-version() { function lookup-version() {
FILE=$1 FILE=$1
VERSION_DATA=$(cat $FILE) VERSION_DATA=$(cat "$FILE")
re="Version[ ]+=[ ]+\"([0-9.]+)\"" re="Version[ ]+=[ ]+\"([0-9.]+)\""
if [[ $VERSION_DATA =~ $re ]]; then if [[ $VERSION_DATA =~ $re ]]; then
VERSION=${BASH_REMATCH[1]} VERSION=${BASH_REMATCH[1]}
echo $VERSION echo "$VERSION"
else else
echo "could not match version" echo "could not match version"
exit exit
fi fi
} }
build $1 $2 $3 build "$1" "$2" "$3"

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAPI/internal/apps" "github.com/TeaOSLab/EdgeAPI/internal/apps"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
@@ -11,7 +12,9 @@ import (
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"io/ioutil"
"log" "log"
"os" "os"
) )
@@ -20,12 +23,12 @@ func main() {
if !Tea.IsTesting() { if !Tea.IsTesting() {
Tea.Env = "prod" Tea.Env = "prod"
} }
app := apps.NewAppCmd() var app = apps.NewAppCmd()
app.Version(teaconst.Version) app.Version(teaconst.Version)
app.Product(teaconst.ProductName) app.Product(teaconst.ProductName)
app.Usage(teaconst.ProcessName + " [start|stop|restart|setup|upgrade|service|daemon]") app.Usage(teaconst.ProcessName + " [start|stop|restart|setup|upgrade|service|daemon|issues]")
app.On("setup", func() { app.On("setup", func() {
setupCmd := setup.NewSetupFromCmd() var setupCmd = setup.NewSetupFromCmd()
err := setupCmd.Run() err := setupCmd.Run()
result := maps.Map{} result := maps.Map{}
if err != nil { if err != nil {
@@ -97,6 +100,68 @@ func main() {
} }
} }
}) })
app.On("db.stmt.prepare", func() {
var sock = gosock.NewTmpSock(teaconst.ProcessName)
reply, err := sock.Send(&gosock.Command{Code: "db.stmt.prepare"})
if err != nil {
fmt.Println("[ERROR]" + err.Error())
} else {
var isOn = maps.NewMap(reply.Params).GetBool("isOn")
if isOn {
fmt.Println("show statements: on")
} else {
fmt.Println("show statements: off")
}
}
})
app.On("db.stmt.count", func() {
var sock = gosock.NewTmpSock(teaconst.ProcessName)
reply, err := sock.Send(&gosock.Command{Code: "db.stmt.count"})
if err != nil {
fmt.Println("[ERROR]" + err.Error())
} else {
var count = maps.NewMap(reply.Params).GetInt("count")
fmt.Println("prepared statements count: " + types.String(count))
}
})
app.On("issues", func() {
var flagSet = flag.NewFlagSet("issues", flag.ExitOnError)
var formatJSON = false
flagSet.BoolVar(&formatJSON, "json", false, "")
_ = flagSet.Parse(os.Args[2:])
data, err := ioutil.ReadFile(Tea.LogFile("issues.log"))
if err != nil {
if formatJSON {
fmt.Print("[]")
} else {
fmt.Println("no issues yet")
}
} else {
var issueMaps = []maps.Map{}
err = json.Unmarshal(data, &issueMaps)
if err != nil {
if formatJSON {
fmt.Print("[]")
} else {
fmt.Println("no issues yet")
}
} else {
if formatJSON {
fmt.Print(string(data))
} else {
if len(issueMaps) == 0 {
fmt.Println("no issues yet")
} else {
for i, issue := range issueMaps {
fmt.Println("issue " + types.String(i+1) + ": " + issue.GetString("message"))
}
}
}
}
}
})
app.Run(func() { app.Run(func() {
nodes.NewAPINode().Start() nodes.NewAPINode().Start()
}) })

1
dist/.gitignore vendored
View File

@@ -1 +1,2 @@
*.zip *.zip
edge-api

30
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/TeaOSLab/EdgeAPI module github.com/TeaOSLab/EdgeAPI
go 1.15 go 1.18
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
@@ -12,16 +12,36 @@ require (
github.com/go-acme/lego/v4 v4.5.2 github.com/go-acme/lego/v4 v4.5.2
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
github.com/golang/protobuf v1.5.2 github.com/golang/protobuf v1.5.2
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
github.com/json-iterator/go v1.1.12 // indirect
github.com/mozillazg/go-pinyin v0.18.0 github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0 github.com/pkg/sftp v1.12.0
github.com/shirou/gopsutil/v3 v3.22.2 // indirect github.com/shirou/gopsutil/v3 v3.22.2
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
google.golang.org/grpc v1.45.0 google.golang.org/grpc v1.45.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )
require (
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // 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/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
)

21
go.sum
View File

@@ -66,7 +66,6 @@ github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7F
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 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 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 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -176,7 +175,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
@@ -238,8 +236,9 @@ github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhK
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc= github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc= github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570 h1:zqz2FiMMkSHXWO1EsTRJDPTwX9xQ4uuyD5GAE4JGlhM=
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c= github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA= github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
@@ -283,6 +282,7 @@ github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9
github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ= github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc= github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc=
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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@@ -371,6 +371,7 @@ github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -398,8 +399,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks= github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks=
github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -440,12 +439,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -561,7 +556,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -627,7 +621,6 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -635,8 +628,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -735,8 +726,6 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc h1:fb/ViRpv3ln/LvbqZtTpoOd1YQDNH12gaGZreoSFovE=
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg=
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -750,8 +739,6 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=

View File

@@ -12,8 +12,9 @@ import (
) )
type BaseStorage struct { type BaseStorage struct {
isOk bool isOk bool
version int version int
firewallOnly bool
} }
func (this *BaseStorage) SetVersion(version int) { func (this *BaseStorage) SetVersion(version int) {
@@ -32,6 +33,10 @@ func (this *BaseStorage) SetOk(isOk bool) {
this.isOk = isOk this.isOk = isOk
} }
func (this *BaseStorage) SetFirewallOnly(firewallOnly bool) {
this.firewallOnly = firewallOnly
}
// Marshal 对日志进行编码 // Marshal 对日志进行编码
func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) { func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) {
return json.Marshal(accessLog) return json.Marshal(accessLog)
@@ -39,7 +44,7 @@ func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) {
// FormatVariables 格式化字符串中的变量 // FormatVariables 格式化字符串中的变量
func (this *BaseStorage) FormatVariables(s string) string { func (this *BaseStorage) FormatVariables(s string) string {
now := time.Now() var now = time.Now()
return configutils.ParseVariables(s, func(varName string) (value string) { return configutils.ParseVariables(s, func(varName string) (value string) {
switch varName { switch varName {
case "year": case "year":

View File

@@ -61,6 +61,10 @@ func (this *CommandStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
return err return err
} }
for _, accessLog := range accessLogs { for _, accessLog := range accessLogs {
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
continue
}
data, err := this.Marshal(accessLog) data, err := this.Marshal(accessLog)
if err != nil { if err != nil {
logs.Error(err) logs.Error(err)

View File

@@ -59,6 +59,10 @@ func (this *ESStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
indexName := this.FormatVariables(this.config.Index) indexName := this.FormatVariables(this.config.Index)
typeName := this.FormatVariables(this.config.MappingType) typeName := this.FormatVariables(this.config.MappingType)
for _, accessLog := range accessLogs { for _, accessLog := range accessLogs {
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
continue
}
if len(accessLog.RequestId) == 0 { if len(accessLog.RequestId) == 0 {
continue continue
} }

View File

@@ -57,6 +57,9 @@ func (this *FileStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
defer this.writeLocker.Unlock() defer this.writeLocker.Unlock()
for _, accessLog := range accessLogs { for _, accessLog := range accessLogs {
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
continue
}
data, err := this.Marshal(accessLog) data, err := this.Marshal(accessLog)
if err != nil { if err != nil {
logs.Error(err) logs.Error(err)

View File

@@ -12,6 +12,9 @@ type StorageInterface interface {
// SetVersion 设置版本 // SetVersion 设置版本
SetVersion(version int) SetVersion(version int)
// SetFirewallOnly 设置是否只处理防火墙相关的访问日志
SetFirewallOnly(firewallOnly bool)
IsOk() bool IsOk() bool
SetOk(ok bool) SetOk(ok bool)

View File

@@ -58,7 +58,7 @@ func (this *StorageManager) Loop() error {
} }
var policyIds = []int64{} var policyIds = []int64{}
for _, policy := range policies { for _, policy := range policies {
if policy.IsOn == 1 { if policy.IsOn {
policyIds = append(policyIds, int64(policy.Id)) policyIds = append(policyIds, int64(policy.Id))
} }
} }
@@ -92,7 +92,7 @@ func (this *StorageManager) Loop() error {
} }
if len(policy.Options) > 0 { if len(policy.Options) > 0 {
err = json.Unmarshal([]byte(policy.Options), storage.Config()) err = json.Unmarshal(policy.Options, storage.Config())
if err != nil { if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "unmarshal policy '"+types.String(policyId)+"' config failed: "+err.Error()) remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "unmarshal policy '"+types.String(policyId)+"' config failed: "+err.Error())
storage.SetOk(false) storage.SetOk(false)
@@ -101,6 +101,7 @@ func (this *StorageManager) Loop() error {
} }
storage.SetVersion(types.Int(policy.Version)) storage.SetVersion(types.Int(policy.Version))
storage.SetFirewallOnly(policy.FirewallOnly == 1)
err := storage.Start() err := storage.Start()
if err != nil { if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error()) remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error())
@@ -110,12 +111,13 @@ func (this *StorageManager) Loop() error {
remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "restart policy '"+types.String(policyId)+"'") remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "restart policy '"+types.String(policyId)+"'")
} }
} else { } else {
storage, err := this.createStorage(policy.Type, []byte(policy.Options)) storage, err := this.createStorage(policy.Type, policy.Options)
if err != nil { if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "create policy '"+types.String(policyId)+"' failed: "+err.Error()) remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "create policy '"+types.String(policyId)+"' failed: "+err.Error())
continue continue
} }
storage.SetVersion(types.Int(policy.Version)) storage.SetVersion(types.Int(policy.Version))
storage.SetFirewallOnly(policy.FirewallOnly == 1)
this.storageMap[policyId] = storage this.storageMap[policyId] = storage
err = storage.Start() err = storage.Start()
if err != nil { if err != nil {

View File

@@ -1,7 +1,9 @@
package accesslogs package accesslogs
import ( import (
"bytes"
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
@@ -95,7 +97,10 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
args = append(args, "-S", "10240") args = append(args, "-S", "10240")
cmd := exec.Command(this.exe, args...) var cmd = exec.Command(this.exe, args...)
var stderrBuffer = &bytes.Buffer{}
cmd.Stderr = stderrBuffer
w, err := cmd.StdinPipe() w, err := cmd.StdinPipe()
if err != nil { if err != nil {
return err return err
@@ -106,9 +111,12 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
} }
for _, accessLog := range accessLogs { for _, accessLog := range accessLogs {
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
continue
}
data, err := this.Marshal(accessLog) data, err := this.Marshal(accessLog)
if err != nil { if err != nil {
logs.Error(err) remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "marshal accesslog failed: "+err.Error())
continue continue
} }
_, err = w.Write(data) _, err = w.Write(data)
@@ -118,14 +126,15 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
_, err = w.Write([]byte("\n")) _, err = w.Write([]byte("\n"))
if err != nil { if err != nil {
logs.Error(err) remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "write accesslog failed: "+err.Error())
} }
} }
_ = w.Close() _ = w.Close()
err = cmd.Wait() err = cmd.Wait()
if err != nil { if err != nil {
return err return errors.New("send syslog failed: " + err.Error() + ", stderr: " + stderrBuffer.String())
} }
return nil return nil

View File

@@ -60,6 +60,9 @@ func (this *TCPStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
defer this.writeLocker.Unlock() defer this.writeLocker.Unlock()
for _, accessLog := range accessLogs { for _, accessLog := range accessLogs {
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
continue
}
data, err := this.Marshal(accessLog) data, err := this.Marshal(accessLog)
if err != nil { if err != nil {
logs.Error(err) logs.Error(err)

View File

@@ -1,51 +1,108 @@
package apps package apps
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/utils/sizes"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/files"
"github.com/iwind/TeaGo/logs" timeutil "github.com/iwind/TeaGo/utils/time"
"github.com/iwind/TeaGo/utils/time"
"log" "log"
"os"
"runtime"
"strconv"
"strings"
) )
type LogWriter struct { type LogWriter struct {
fileAppender *files.Appender fp *os.File
c chan string
} }
func (this *LogWriter) Init() { func (this *LogWriter) Init() {
// 创建目录 // 创建目录
dir := files.NewFile(Tea.LogDir()) var dir = files.NewFile(Tea.LogDir())
if !dir.Exists() { if !dir.Exists() {
err := dir.Mkdir() err := dir.Mkdir()
if err != nil { if err != nil {
log.Println("[error]" + err.Error()) log.Println("[LOG]create log dir failed: " + err.Error())
} }
} }
logFile := files.NewFile(Tea.LogFile("run.log"))
// 打开要写入的日志文件 // 打开要写入的日志文件
appender, err := logFile.Appender() var logPath = Tea.LogFile("run.log")
fp, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { if err != nil {
logs.Error(err) log.Println("[LOG]open log file failed: " + err.Error())
} else { } else {
this.fileAppender = appender this.fp = fp
}
this.c = make(chan string, 1024)
// 异步写入文件
var maxFileSize = 2 * sizes.G // 文件最大尺寸,超出此尺寸则清空
if fp != nil {
goman.New(func() {
var totalSize int64 = 0
stat, err := fp.Stat()
if err == nil {
totalSize = stat.Size()
}
for message := range this.c {
totalSize += int64(len(message))
_, err := fp.WriteString(timeutil.Format("Y/m/d H:i:s ") + message + "\n")
if err != nil {
log.Println("[LOG]write log failed: " + err.Error())
} else {
// 如果太大则Truncate
if totalSize > maxFileSize {
_ = fp.Truncate(0)
totalSize = 0
}
}
}
})
} }
} }
func (this *LogWriter) Write(message string) { func (this *LogWriter) Write(message string) {
log.Println(message) backgroundEnv, _ := os.LookupEnv("EdgeBackground")
if backgroundEnv != "on" {
// 文件和行号
var file string
var line int
if Tea.IsTesting() {
var callDepth = 3
var ok bool
_, file, line, ok = runtime.Caller(callDepth)
if ok {
file = this.packagePath(file)
}
}
if this.fileAppender != nil { if len(file) > 0 {
_, err := this.fileAppender.AppendString(timeutil.Format("Y/m/d H:i:s ") + message + "\n") log.Println(message + " (" + file + ":" + strconv.Itoa(line) + ")")
if err != nil { } else {
log.Println("[error]" + err.Error()) log.Println(message)
} }
} }
this.c <- message
} }
func (this *LogWriter) Close() { func (this *LogWriter) Close() {
if this.fileAppender != nil { if this.fp != nil {
_ = this.fileAppender.Close() _ = this.fp.Close()
} }
close(this.c)
}
func (this *LogWriter) packagePath(path string) string {
var pieces = strings.Split(path, "/")
if len(pieces) >= 2 {
return strings.Join(pieces[len(pieces)-2:], "/")
}
return path
} }

View File

@@ -1,7 +1,7 @@
package teaconst package teaconst
const ( const (
Version = "0.4.5" Version = "0.4.9"
ProductName = "Edge API" ProductName = "Edge API"
ProcessName = "edge-api" ProcessName = "edge-api"
@@ -18,13 +18,13 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点 // 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.4.5" NodeVersion = "0.4.9"
UserNodeVersion = "0.3.2" UserNodeVersion = "0.3.5"
AuthorityNodeVersion = "0.0.2" AuthorityNodeVersion = "0.0.2"
MonitorNodeVersion = "0.0.3" MonitorNodeVersion = "0.0.4"
DNSNodeVersion = "0.2.1" DNSNodeVersion = "0.2.4"
ReportNodeVersion = "0.1.0" ReportNodeVersion = "0.1.1"
// SQLVersion SQL版本号 // SQLVersion SQL版本号
SQLVersion = "5" SQLVersion = "2"
) )

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"database/sql" "database/sql"
"database/sql/driver" "database/sql/driver"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
@@ -42,3 +43,13 @@ func TestDB_Instance(t *testing.T) {
} }
time.Sleep(100 * time.Second) time.Sleep(100 * time.Second)
} }
func TestDB_Reuse(t *testing.T) {
var dao = models.NewVersionDAO()
for i := 0; i < 20_000; i++ {
_, _, err := dao.Query(nil).Attr("version", i).Reuse(true).FindOne()
if err != nil {
t.Fatal(err)
}
}
}

View File

@@ -2,6 +2,7 @@ package accounts
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@@ -79,7 +80,7 @@ func (this *UserAccountLogDAO) CountAccountLogs(tx *dbs.Tx, userId int64, accoun
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)") query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
query.Param("keyword", "%"+keyword+"%") query.Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(eventType) > 0 { if len(eventType) > 0 {
query.Attr("eventType", eventType) query.Attr("eventType", eventType)
@@ -98,7 +99,7 @@ func (this *UserAccountLogDAO) ListAccountLogs(tx *dbs.Tx, userId int64, account
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)") query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
query.Param("keyword", "%"+keyword+"%") query.Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(eventType) > 0 { if len(eventType) > 0 {
query.Attr("eventType", eventType) query.Attr("eventType", eventType)

View File

@@ -1,19 +1,21 @@
package accounts package accounts
import "github.com/iwind/TeaGo/dbs"
// UserAccountLog 用户账户日志 // UserAccountLog 用户账户日志
type UserAccountLog struct { type UserAccountLog struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID UserId uint64 `field:"userId"` // 用户ID
AccountId uint64 `field:"accountId"` // 账户ID AccountId uint64 `field:"accountId"` // 账户ID
Delta float64 `field:"delta"` // 操作余额的数量(可为负) Delta float64 `field:"delta"` // 操作余额的数量(可为负)
DeltaFrozen float64 `field:"deltaFrozen"` // 操作冻结的数量(可为负) DeltaFrozen float64 `field:"deltaFrozen"` // 操作冻结的数量(可为负)
Total float64 `field:"total"` // 操作后余额 Total float64 `field:"total"` // 操作后余额
TotalFrozen float64 `field:"totalFrozen"` // 操作后冻结余额 TotalFrozen float64 `field:"totalFrozen"` // 操作后冻结余额
EventType string `field:"eventType"` // 类型 EventType string `field:"eventType"` // 类型
Description string `field:"description"` // 描述文字 Description string `field:"description"` // 描述文字
Day string `field:"day"` // YYYYMMDD Day string `field:"day"` // YYYYMMDD
CreatedAt uint64 `field:"createdAt"` // 时间 CreatedAt uint64 `field:"createdAt"` // 时间
Params string `field:"params"` // 参数 Params dbs.JSON `field:"params"` // 参数
} }
type UserAccountLogOperator struct { type UserAccountLogOperator struct {

View File

@@ -3,7 +3,7 @@ package acme
// ACMEProviderAccount ACME提供商 // ACMEProviderAccount ACME提供商
type ACMEProviderAccount struct { type ACMEProviderAccount struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
ProviderCode string `field:"providerCode"` // 代号 ProviderCode string `field:"providerCode"` // 代号
Error string `field:"error"` // 最后一条错误信息 Error string `field:"error"` // 最后一条错误信息

View File

@@ -125,11 +125,11 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, use
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(domains LIKE :keyword)"). query.Where("(domains LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("domains LIKE :keyword"). query.Where("domains LIKE :keyword").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
return query.State(ACMETaskStateEnabled). return query.State(ACMETaskStateEnabled).
@@ -155,7 +155,7 @@ func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(domains LIKE :keyword)"). query.Where("(domains LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
_, err = query. _, err = query.
State(ACMETaskStateEnabled). State(ACMETaskStateEnabled).
@@ -271,7 +271,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
errMsg = "找不到要执行的任务" errMsg = "找不到要执行的任务"
return return
} }
if task.IsOn != 1 { if !task.IsOn {
errMsg = "任务没有启用" errMsg = "任务没有启用"
return return
} }
@@ -330,7 +330,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
}) })
if len(user.Registration) > 0 { if len(user.Registration) > 0 {
err = remoteUser.SetRegistration([]byte(user.Registration)) err = remoteUser.SetRegistration(user.Registration)
if err != nil { if err != nil {
errMsg = "设置注册信息时出错:" + err.Error() errMsg = "设置注册信息时出错:" + err.Error()
return return
@@ -453,7 +453,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
return return
} }
err = models.SharedSSLCertDAO.UpdateCert(tx, resultCertId, cert.IsOn == 1, cert.Name, cert.Description, cert.ServerName, cert.IsCA == 1, certData, keyData, sslConfig.TimeBeginAt, sslConfig.TimeEndAt, sslConfig.DNSNames, sslConfig.CommonNames) err = models.SharedSSLCertDAO.UpdateCert(tx, resultCertId, cert.IsOn, cert.Name, cert.Description, cert.ServerName, cert.IsCA, certData, keyData, sslConfig.TimeBeginAt, sslConfig.TimeEndAt, sslConfig.DNSNames, sslConfig.CommonNames)
if err != nil { if err != nil {
errMsg = "证书生成成功,但是修改数据库中的证书信息时出错:" + err.Error() errMsg = "证书生成成功,但是修改数据库中的证书信息时出错:" + err.Error()
return return

View File

@@ -1,10 +1,10 @@
package acme package acme
// ACME任务运行日志 // ACMETaskLog ACME任务运行日志
type ACMETaskLog struct { type ACMETaskLog struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
TaskId uint64 `field:"taskId"` // 任务ID TaskId uint64 `field:"taskId"` // 任务ID
IsOk uint8 `field:"isOk"` // 是否成功 IsOk bool `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息 Error string `field:"error"` // 错误信息
CreatedAt uint64 `field:"createdAt"` // 运行时间 CreatedAt uint64 `field:"createdAt"` // 运行时间
} }

View File

@@ -1,21 +1,23 @@
package acme package acme
import "github.com/iwind/TeaGo/dbs"
// ACMETask ACME任务 // ACMETask ACME任务
type ACMETask struct { type ACMETask struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
AcmeUserId uint32 `field:"acmeUserId"` // ACME用户ID AcmeUserId uint32 `field:"acmeUserId"` // ACME用户ID
DnsDomain string `field:"dnsDomain"` // DNS主域名 DnsDomain string `field:"dnsDomain"` // DNS主域名
DnsProviderId uint64 `field:"dnsProviderId"` // DNS服务商 DnsProviderId uint64 `field:"dnsProviderId"` // DNS服务商
Domains string `field:"domains"` // 证书域名 Domains dbs.JSON `field:"domains"` // 证书域名
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CertId uint64 `field:"certId"` // 生成的证书ID CertId uint64 `field:"certId"` // 生成的证书ID
AutoRenew uint8 `field:"autoRenew"` // 是否自动更新 AutoRenew uint8 `field:"autoRenew"` // 是否自动更新
AuthType string `field:"authType"` // 认证类型 AuthType string `field:"authType"` // 认证类型
AuthURL string `field:"authURL"` // 认证URL AuthURL string `field:"authURL"` // 认证URL
} }
type ACMETaskOperator struct { type ACMETaskOperator struct {

View File

@@ -5,13 +5,13 @@ import (
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
) )
// 将域名解析成字符串数组 // DecodeDomains 将域名解析成字符串数组
func (this *ACMETask) DecodeDomains() []string { func (this *ACMETask) DecodeDomains() []string {
if len(this.Domains) == 0 || this.Domains == "null" { if len(this.Domains) == 0 {
return nil return nil
} }
result := []string{} result := []string{}
err := json.Unmarshal([]byte(this.Domains), &result) err := json.Unmarshal(this.Domains, &result)
if err != nil { if err != nil {
logs.Error(err) logs.Error(err)
return nil return nil

View File

@@ -1,18 +1,20 @@
package acme package acme
import "github.com/iwind/TeaGo/dbs"
// ACMEUser ACME用户 // ACMEUser ACME用户
type ACMEUser struct { type ACMEUser struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
PrivateKey string `field:"privateKey"` // 私钥 PrivateKey string `field:"privateKey"` // 私钥
Email string `field:"email"` // E-mail Email string `field:"email"` // E-mail
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
Description string `field:"description"` // 备注介绍 Description string `field:"description"` // 备注介绍
Registration string `field:"registration"` // 注册信息 Registration dbs.JSON `field:"registration"` // 注册信息
ProviderCode string `field:"providerCode"` // 服务商代号 ProviderCode string `field:"providerCode"` // 服务商代号
AccountId uint64 `field:"accountId"` // 提供商ID AccountId uint64 `field:"accountId"` // 提供商ID
} }
type ACMEUserOperator struct { type ACMEUserOperator struct {

View File

@@ -1,19 +1,21 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// Admin 管理员 // Admin 管理员
type Admin struct { type Admin struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Username string `field:"username"` // 用户名 Username string `field:"username"` // 用户名
Password string `field:"password"` // 密码 Password string `field:"password"` // 密码
Fullname string `field:"fullname"` // 全名 Fullname string `field:"fullname"` // 全名
IsSuper uint8 `field:"isSuper"` // 是否为超级管理员 IsSuper bool `field:"isSuper"` // 是否为超级管理员
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
UpdatedAt uint64 `field:"updatedAt"` // 修改时间 UpdatedAt uint64 `field:"updatedAt"` // 修改时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
Modules string `field:"modules"` // 允许的模块 Modules dbs.JSON `field:"modules"` // 允许的模块
CanLogin uint8 `field:"canLogin"` // 是否可以登录 CanLogin uint8 `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置 Theme string `field:"theme"` // 模板设置
} }
type AdminOperator struct { type AdminOperator struct {

View File

@@ -3,6 +3,8 @@ package models
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/configs"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@@ -49,16 +51,29 @@ func (this *APINodeDAO) EnableAPINode(tx *dbs.Tx, id int64) error {
Pk(id). Pk(id).
Set("state", APINodeStateEnabled). Set("state", APINodeStateEnabled).
Update() Update()
return err if err != nil {
return err
}
return this.NotifyUpdate(tx, id)
} }
// DisableAPINode 禁用条目 // DisableAPINode 禁用条目
func (this *APINodeDAO) DisableAPINode(tx *dbs.Tx, id int64) error { func (this *APINodeDAO) DisableAPINode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", APINodeStateDisabled). Set("state", APINodeStateDisabled).
Update() Update()
return err if err != nil {
return err
}
err = this.NotifyUpdate(tx, nodeId)
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleAPI, nodeId)
} }
// FindEnabledAPINode 查找启用中的条目 // FindEnabledAPINode 查找启用中的条目
@@ -149,16 +164,33 @@ func (this *APINodeDAO) CreateAPINode(tx *dbs.Tx, name string, description strin
return return
} }
err = this.NotifyUpdate(tx, types.Int64(op.Id))
if err != nil {
remotelogs.Error("API_NODE_DAO", err.Error())
}
return types.Int64(op.Id), nil return types.Int64(op.Id), nil
} }
// UpdateAPINode 修改API节点 // UpdateAPINode 修改API节点
func (this *APINodeDAO) UpdateAPINode(tx *dbs.Tx, nodeId int64, name string, description string, httpJSON []byte, httpsJSON []byte, restIsOn bool, restHTTPJSON []byte, restHTTPSJSON []byte, accessAddrsJSON []byte, isOn bool) error { func (this *APINodeDAO) UpdateAPINode(tx *dbs.Tx, nodeId int64, name string, description string, httpJSON []byte, httpsJSON []byte, restIsOn bool, restHTTPJSON []byte, restHTTPSJSON []byte, accessAddrsJSON []byte, isOn bool, isPrimary bool) error {
if nodeId <= 0 { if nodeId <= 0 {
return errors.New("invalid nodeId") return errors.New("invalid nodeId")
} }
op := NewAPINodeOperator() // 取消别的Primary
if isPrimary {
err := this.Query(tx).
Neq("id", nodeId).
Attr("isPrimary", true).
Set("isPrimary", false).
UpdateQuickly()
if err != nil {
return err
}
}
var op = NewAPINodeOperator()
op.Id = nodeId op.Id = nodeId
op.Name = name op.Name = name
op.Description = description op.Description = description
@@ -191,8 +223,13 @@ func (this *APINodeDAO) UpdateAPINode(tx *dbs.Tx, nodeId int64, name string, des
op.AccessAddrs = "[]" op.AccessAddrs = "[]"
} }
op.IsPrimary = isPrimary
err := this.Save(tx, op) err := this.Save(tx, op)
return err if err != nil {
return err
}
return this.NotifyUpdate(tx, nodeId)
} }
// FindAllEnabledAPINodes 列出所有可用API节点 // FindAllEnabledAPINodes 列出所有可用API节点
@@ -294,23 +331,6 @@ func (this *APINodeDAO) UpdateAPINodeStatus(tx *dbs.Tx, apiNodeId int64, statusJ
return err return err
} }
// 生成唯一ID
func (this *APINodeDAO) genUniqueId(tx *dbs.Tx) (string, error) {
for {
uniqueId := rands.HexString(32)
ok, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Exist()
if err != nil {
return "", err
}
if ok {
continue
}
return uniqueId, nil
}
}
// CountAllLowerVersionNodes 计算所有节点中低于某个版本的节点数量 // CountAllLowerVersionNodes 计算所有节点中低于某个版本的节点数量
func (this *APINodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) { func (this *APINodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx). return this.Query(tx).
@@ -384,3 +404,114 @@ func (this *APINodeDAO) FindAllEnabledAPIAccessIPs(tx *dbs.Tx, cacheMap *utils.C
return result, nil return result, nil
} }
// CheckAPINodeIsPrimary 检查当前节点是否为Primary节点
func (this *APINodeDAO) CheckAPINodeIsPrimary(tx *dbs.Tx) (bool, error) {
config, err := configs.SharedAPIConfig()
if err != nil {
return false, err
}
isPrimary, err := this.Query(tx).
State(APINodeStateEnabled).
Attr("uniqueId", config.NodeId).
Attr("isPrimary", true).
Exist()
if err != nil {
return false, err
}
if isPrimary {
return true, nil
}
// 检查是否有别的Primary节点
count, err := this.Query(tx).
State(APINodeStateEnabled).
Attr("isOn", true).
Attr("isPrimary", true).
Count()
if err != nil {
return false, err
}
if count == 0 {
err = this.ResetPrimaryAPINode(tx)
if err != nil {
return false, err
}
return true, nil
}
return false, nil
}
// CheckAPINodeIsPrimaryWithoutErr 检查当前节点是否为Primary节点并忽略错误
func (this *APINodeDAO) CheckAPINodeIsPrimaryWithoutErr() bool {
b, err := this.CheckAPINodeIsPrimary(nil)
return b && err == nil
}
// ResetPrimaryAPINode 重置Primary节点
func (this *APINodeDAO) ResetPrimaryAPINode(tx *dbs.Tx) error {
// 当前是否有Primary节点
apiNode, err := this.Query(tx).
State(APINodeStateEnabled).
Attr("isOn", true).
Attr("isPrimary", true).
Find()
if err != nil {
return err
}
if apiNode == nil {
// 选择一个作为Primary
// TODO 将来需要考虑API节点离线的情况
apiNodeId, err := this.Query(tx).
State(APINodeStateEnabled).
Attr("isOn", true).
ResultPk().
FindInt64Col(0)
if err != nil {
return err
}
if apiNodeId > 0 {
err = this.Query(tx).
Pk(apiNodeId).
Set("isPrimary", true).
UpdateQuickly()
if err != nil {
return err
}
}
}
return nil
}
// NotifyUpdate 通知变更
func (this *APINodeDAO) NotifyUpdate(tx *dbs.Tx, apiNodeId int64) error {
// suppress IDE warning
_ = apiNodeId
err := this.ResetPrimaryAPINode(tx)
if err != nil {
return err
}
return nil
}
// 生成唯一ID
func (this *APINodeDAO) genUniqueId(tx *dbs.Tx) (string, error) {
for {
uniqueId := rands.HexString(32)
ok, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Exist()
if err != nil {
return "", err
}
if ok {
continue
}
return uniqueId, nil
}
}

View File

@@ -34,6 +34,16 @@ func TestAPINodeDAO_FindAllEnabledAPIAccessIPs(t *testing.T) {
t.Log(NewAPINodeDAO().FindAllEnabledAPIAccessIPs(nil, cacheMap)) t.Log(NewAPINodeDAO().FindAllEnabledAPIAccessIPs(nil, cacheMap))
} }
func TestAPINodeDAO_CheckAPINodeIsPrimary(t *testing.T) {
var dao = NewAPINodeDAO()
t.Log(dao.CheckAPINodeIsPrimary(nil))
}
func TestAPINodeDAO_ResetPrimaryAPINode(t *testing.T) {
var dao = NewAPINodeDAO()
t.Log(dao.ResetPrimaryAPINode(nil))
}
func BenchmarkAPINodeDAO_New(b *testing.B) { func BenchmarkAPINodeDAO_New(b *testing.B) {
runtime.GOMAXPROCS(1) runtime.GOMAXPROCS(1)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View File

@@ -1,26 +1,29 @@
package models package models
// API节点 import "github.com/iwind/TeaGo/dbs"
// APINode API节点
type APINode struct { type APINode struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
ClusterId uint32 `field:"clusterId"` // 专用集群ID ClusterId uint32 `field:"clusterId"` // 专用集群ID
UniqueId string `field:"uniqueId"` // 唯一ID UniqueId string `field:"uniqueId"` // 唯一ID
Secret string `field:"secret"` // 密钥 Secret string `field:"secret"` // 密钥
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Http string `field:"http"` // 监听的HTTP配置 Http dbs.JSON `field:"http"` // 监听的HTTP配置
Https string `field:"https"` // 监听的HTTPS配置 Https dbs.JSON `field:"https"` // 监听的HTTPS配置
RestIsOn uint8 `field:"restIsOn"` // 是否开放REST RestIsOn uint8 `field:"restIsOn"` // 是否开放REST
RestHTTP string `field:"restHTTP"` // REST HTTP配置 RestHTTP dbs.JSON `field:"restHTTP"` // REST HTTP配置
RestHTTPS string `field:"restHTTPS"` // REST HTTPS配置 RestHTTPS dbs.JSON `field:"restHTTPS"` // REST HTTPS配置
AccessAddrs string `field:"accessAddrs"` // 外部访问地址 AccessAddrs dbs.JSON `field:"accessAddrs"` // 外部访问地址
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
Weight uint32 `field:"weight"` // 权重 Weight uint32 `field:"weight"` // 权重
Status string `field:"status"` // 运行状态 Status dbs.JSON `field:"status"` // 运行状态
IsPrimary bool `field:"isPrimary"` // 是否为主API节点
} }
type APINodeOperator struct { type APINodeOperator struct {
@@ -43,6 +46,7 @@ type APINodeOperator struct {
AdminId interface{} // 管理员ID AdminId interface{} // 管理员ID
Weight interface{} // 权重 Weight interface{} // 权重
Status interface{} // 运行状态 Status interface{} // 运行状态
IsPrimary interface{} // 是否为主API节点
} }
func NewAPINodeOperator() *APINodeOperator { func NewAPINodeOperator() *APINodeOperator {

View File

@@ -13,7 +13,7 @@ func (this *APINode) DecodeHTTP() (*serverconfigs.HTTPProtocolConfig, error) {
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPProtocolConfig{} config := &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal([]byte(this.Http), config) err := json.Unmarshal(this.Http, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -32,7 +32,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPSProtocolConfig{} config := &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal([]byte(this.Https), config) err := json.Unmarshal(this.Https, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -70,7 +70,7 @@ func (this *APINode) DecodeAccessAddrs() ([]*serverconfigs.NetworkAddressConfig,
} }
addrConfigs := []*serverconfigs.NetworkAddressConfig{} addrConfigs := []*serverconfigs.NetworkAddressConfig{}
err := json.Unmarshal([]byte(this.AccessAddrs), &addrConfigs) err := json.Unmarshal(this.AccessAddrs, &addrConfigs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -105,7 +105,7 @@ func (this *APINode) DecodeRestHTTP() (*serverconfigs.HTTPProtocolConfig, error)
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPProtocolConfig{} config := &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal([]byte(this.RestHTTP), config) err := json.Unmarshal(this.RestHTTP, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -130,7 +130,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPSProtocolConfig{} config := &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal([]byte(this.RestHTTPS), config) err := json.Unmarshal(this.RestHTTPS, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,15 +1,17 @@
package authority package authority
import "github.com/iwind/TeaGo/dbs"
// AuthorityKey 企业版认证信息 // AuthorityKey 企业版认证信息
type AuthorityKey struct { type AuthorityKey struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Value string `field:"value"` // Key值 Value string `field:"value"` // Key值
DayFrom string `field:"dayFrom"` // 开始日期 DayFrom string `field:"dayFrom"` // 开始日期
DayTo string `field:"dayTo"` // 结束日期 DayTo string `field:"dayTo"` // 结束日期
Hostname string `field:"hostname"` // Hostname Hostname string `field:"hostname"` // Hostname
MacAddresses string `field:"macAddresses"` // MAC地址 MacAddresses dbs.JSON `field:"macAddresses"` // MAC地址
UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间 UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间
Company string `field:"company"` // 公司组织 Company string `field:"company"` // 公司组织
} }
type AuthorityKeyOperator struct { type AuthorityKeyOperator struct {

View File

@@ -1,6 +1,7 @@
package authority package authority
import ( import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
@@ -188,13 +189,19 @@ func (this *AuthorityNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
} }
// UpdateNodeStatus 更改节点状态 // UpdateNodeStatus 更改节点状态
func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error { func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if statusJSON == nil { if nodeStatus == nil {
return nil return nil
} }
_, err := this.Query(tx).
nodeStatusJSON, err := json.Marshal(nodeStatus)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(nodeId). Pk(nodeId).
Set("status", string(statusJSON)). Set("status", nodeStatusJSON).
Update() Update()
return err return err
} }

View File

@@ -1,19 +1,21 @@
package authority package authority
import "github.com/iwind/TeaGo/dbs"
// AuthorityNode 监控节点 // AuthorityNode 监控节点
type AuthorityNode struct { type AuthorityNode struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
UniqueId string `field:"uniqueId"` // 唯一ID UniqueId string `field:"uniqueId"` // 唯一ID
Secret string `field:"secret"` // 密钥 Secret string `field:"secret"` // 密钥
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
Weight uint32 `field:"weight"` // 权重 Weight uint32 `field:"weight"` // 权重
Status string `field:"status"` // 运行状态 Status dbs.JSON `field:"status"` // 运行状态
} }
type AuthorityNodeOperator struct { type AuthorityNodeOperator struct {

View File

@@ -1,11 +1,13 @@
package models package models
// 终端浏览器信息 import "github.com/iwind/TeaGo/dbs"
// ClientBrowser 终端浏览器信息
type ClientBrowser struct { type ClientBrowser struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Name string `field:"name"` // 浏览器名称 Name string `field:"name"` // 浏览器名称
Codes string `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
type ClientBrowserOperator struct { type ClientBrowserOperator struct {

View File

@@ -1,11 +1,13 @@
package models package models
// 终端操作系统信息 import "github.com/iwind/TeaGo/dbs"
// ClientSystem 终端操作系统信息
type ClientSystem struct { type ClientSystem struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Name string `field:"name"` // 系统名称 Name string `field:"name"` // 系统名称
Codes string `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
State uint8 `field:"state"` // State uint8 `field:"state"` //
} }
type ClientSystemOperator struct { type ClientSystemOperator struct {

View File

@@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"github.com/TeaOSLab/EdgeAPI/internal/encrypt" "github.com/TeaOSLab/EdgeAPI/internal/encrypt"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -49,12 +50,17 @@ func (this *DBNodeDAO) EnableDBNode(tx *dbs.Tx, id int64) error {
} }
// DisableDBNode 禁用条目 // DisableDBNode 禁用条目
func (this *DBNodeDAO) DisableDBNode(tx *dbs.Tx, id int64) error { func (this *DBNodeDAO) DisableDBNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", DBNodeStateDisabled). Set("state", DBNodeStateDisabled).
Update() Update()
return err if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleDatabase, nodeId)
} }
// FindEnabledDBNode 查找启用中的条目 // FindEnabledDBNode 查找启用中的条目

View File

@@ -56,6 +56,25 @@ func init() {
}) })
} }
func AllAccessLogDBs() []*dbs.DB {
accessLogLocker.Lock()
defer accessLogLocker.Unlock()
var result = []*dbs.DB{}
for _, db := range accessLogDBMapping {
result = append(result, db)
}
if len(result) == 0 {
db, _ := dbs.Default()
if db != nil {
result = append(result, db)
}
}
return result
}
// 获取获取DAO // 获取获取DAO
func randomHTTPAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) { func randomHTTPAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) {
accessLogLocker.RLock() accessLogLocker.RLock()
@@ -237,7 +256,7 @@ func (this *DBNodeInitializer) loop() error {
} }
if db == nil { if db == nil {
config := &dbs.DBConfig{ var config = &dbs.DBConfig{
Driver: "mysql", Driver: "mysql",
Dsn: dsn, Dsn: dsn,
Prefix: "edge", Prefix: "edge",
@@ -251,7 +270,7 @@ func (this *DBNodeInitializer) loop() error {
// 检查表是否存在 // 检查表是否存在
// httpAccessLog // httpAccessLog
{ {
tableDef, err := SharedHTTPAccessLogManager.FindTable(db, timeutil.Format("Ymd"), true) tableDef, err := SharedHTTPAccessLogManager.FindLastTable(db, timeutil.Format("Ymd"), true)
if err != nil { if err != nil {
remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error()) remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error())

View File

@@ -1,9 +1,9 @@
package models package models
// 数据库节点 // DBNode 数据库节点
type DBNode struct { type DBNode struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Role string `field:"role"` // 数据库角色 Role string `field:"role"` // 数据库角色
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述

View File

@@ -1,22 +1,24 @@
package dns package dns
import "github.com/iwind/TeaGo/dbs"
// DNSDomain 管理的域名 // DNSDomain 管理的域名
type DNSDomain struct { type DNSDomain struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
ProviderId uint32 `field:"providerId"` // 服务商ID ProviderId uint32 `field:"providerId"` // 服务商ID
IsOn uint8 `field:"isOn"` // 是否可用 IsOn bool `field:"isOn"` // 是否可用
Name string `field:"name"` // 域名 Name string `field:"name"` // 域名
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
DataUpdatedAt uint64 `field:"dataUpdatedAt"` // 数据更新时间 DataUpdatedAt uint64 `field:"dataUpdatedAt"` // 数据更新时间
DataError string `field:"dataError"` // 数据更新错误 DataError string `field:"dataError"` // 数据更新错误
Data string `field:"data"` // 原始数据信息 Data string `field:"data"` // 原始数据信息
Records string `field:"records"` // 所有解析记录 Records dbs.JSON `field:"records"` // 所有解析记录
Routes string `field:"routes"` // 线路数据 Routes dbs.JSON `field:"routes"` // 线路数据
IsUp uint8 `field:"isUp"` // 是否在线 IsUp bool `field:"isUp"` // 是否在线
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
IsDeleted uint8 `field:"isDeleted"` // 是否已删除 IsDeleted bool `field:"isDeleted"` // 是否已删除
} }
type DNSDomainOperator struct { type DNSDomainOperator struct {

View File

@@ -7,11 +7,11 @@ import (
// DecodeRoutes 获取所有的线路 // DecodeRoutes 获取所有的线路
func (this *DNSDomain) DecodeRoutes() ([]*dnstypes.Route, error) { func (this *DNSDomain) DecodeRoutes() ([]*dnstypes.Route, error) {
if len(this.Routes) == 0 || this.Routes == "null" { if len(this.Routes) == 0 {
return nil, nil return nil, nil
} }
result := []*dnstypes.Route{} result := []*dnstypes.Route{}
err := json.Unmarshal([]byte(this.Routes), &result) err := json.Unmarshal(this.Routes, &result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -35,11 +35,11 @@ func (this *DNSDomain) ContainsRouteCode(route string) (bool, error) {
// DecodeRecords 获取所有的记录 // DecodeRecords 获取所有的记录
func (this *DNSDomain) DecodeRecords() ([]*dnstypes.Record, error) { func (this *DNSDomain) DecodeRecords() ([]*dnstypes.Record, error) {
records := this.Records records := this.Records
if len(records) == 0 || records == "null" { if len(records) == 0 {
return nil, nil return nil, nil
} }
result := []*dnstypes.Record{} result := []*dnstypes.Record{}
err := json.Unmarshal([]byte(records), &result) err := json.Unmarshal(records, &result)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -107,22 +107,39 @@ func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, n
} }
// CountAllEnabledDNSProviders 计算服务商数量 // CountAllEnabledDNSProviders 计算服务商数量
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string) (int64, error) { func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string, providerType string) (int64, error) {
var query = dbutils.NewQuery(tx, this, adminId, userId) var query = dbutils.NewQuery(tx, this, adminId, userId)
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(domain) > 0 {
query.Where("id IN (SELECT providerId FROM " + SharedDNSDomainDAO.Table + " WHERE state=1 AND name=:domain)")
query.Param("domain", domain)
}
if len(providerType) > 0 {
query.Attr("type", providerType)
}
return query.State(DNSProviderStateEnabled). return query.State(DNSProviderStateEnabled).
Count() Count()
} }
// ListEnabledDNSProviders 列出单页服务商 // ListEnabledDNSProviders 列出单页服务商
func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, offset int64, size int64) (result []*DNSProvider, err error) { func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, domain string, providerType string, offset int64, size int64) (result []*DNSProvider, err error) {
var query = dbutils.NewQuery(tx, this, adminId, userId) var query = dbutils.NewQuery(tx, this, adminId, userId)
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
}
if len(domain) > 0 {
query.Where("id IN (SELECT providerId FROM " + SharedDNSDomainDAO.Table + " WHERE state=1 AND name=:domain)")
query.Param("domain", domain)
}
if len(providerType) > 0 {
query.Attr("type", providerType)
} }
_, err = query. _, err = query.
State(DNSProviderStateEnabled). State(DNSProviderStateEnabled).

View File

@@ -1,16 +1,18 @@
package dns package dns
// DNS服务商 import "github.com/iwind/TeaGo/dbs"
// DNSProvider DNS服务商
type DNSProvider struct { type DNSProvider struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
Type string `field:"type"` // 供应商类型 Type string `field:"type"` // 供应商类型
ApiParams string `field:"apiParams"` // API参数 ApiParams dbs.JSON `field:"apiParams"` // API参数
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
DataUpdatedAt uint64 `field:"dataUpdatedAt"` // 数据同步时间 DataUpdatedAt uint64 `field:"dataUpdatedAt"` // 数据同步时间
} }
type DNSProviderOperator struct { type DNSProviderOperator struct {

View File

@@ -5,12 +5,12 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
) )
// 获取API参数 // DecodeAPIParams 获取API参数
func (this *DNSProvider) DecodeAPIParams() (maps.Map, error) { func (this *DNSProvider) DecodeAPIParams() (maps.Map, error) {
if len(this.ApiParams) == 0 || this.ApiParams == "null" { if len(this.ApiParams) == 0 {
return maps.Map{}, nil return maps.Map{}, nil
} }
result := maps.Map{} result := maps.Map{}
err := json.Unmarshal([]byte(this.ApiParams), &result) err := json.Unmarshal(this.ApiParams, &result)
return result, err return result, err
} }

View File

@@ -12,10 +12,11 @@ import (
type DNSTaskType = string type DNSTaskType = string
const ( const (
DNSTaskTypeClusterChange DNSTaskType = "clusterChange" DNSTaskTypeClusterChange DNSTaskType = "clusterChange"
DNSTaskTypeNodeChange DNSTaskType = "nodeChange" DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
DNSTaskTypeServerChange DNSTaskType = "serverChange" DNSTaskTypeNodeChange DNSTaskType = "nodeChange"
DNSTaskTypeDomainChange DNSTaskType = "domainChange" DNSTaskTypeServerChange DNSTaskType = "serverChange"
DNSTaskTypeDomainChange DNSTaskType = "domainChange"
) )
type DNSTaskDAO dbs.DAO type DNSTaskDAO dbs.DAO
@@ -40,20 +41,21 @@ func init() {
} }
// CreateDNSTask 生成任务 // CreateDNSTask 生成任务
func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int64, nodeId int64, domainId int64, taskType string) error { func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int64, nodeId int64, domainId int64, recordName string, taskType string) error {
if clusterId <= 0 && serverId <= 0 && nodeId <= 0 && domainId <= 0 { if clusterId <= 0 && serverId <= 0 && nodeId <= 0 && domainId <= 0 {
return nil return nil
} }
err := this.Query(tx).InsertOrUpdateQuickly(maps.Map{ err := this.Query(tx).InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId, "clusterId": clusterId,
"serverId": serverId, "serverId": serverId,
"nodeId": nodeId, "nodeId": nodeId,
"domainId": domainId, "domainId": domainId,
"updatedAt": time.Now().Unix(), "recordName": recordName,
"type": taskType, "updatedAt": time.Now().Unix(),
"isDone": false, "type": taskType,
"isOk": false, "isDone": false,
"error": "", "isOk": false,
"error": "",
}, maps.Map{ }, maps.Map{
"updatedAt": time.Now().Unix(), "updatedAt": time.Now().Unix(),
"isDone": false, "isDone": false,
@@ -63,24 +65,29 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
return err return err
} }
// CreateClusterTask 生成集群任务 // CreateClusterTask 生成集群变更任务
func (this *DNSTaskDAO) CreateClusterTask(tx *dbs.Tx, clusterId int64, taskType DNSTaskType) error { func (this *DNSTaskDAO) CreateClusterTask(tx *dbs.Tx, clusterId int64, taskType DNSTaskType) error {
return this.CreateDNSTask(tx, clusterId, 0, 0, 0, taskType) return this.CreateDNSTask(tx, clusterId, 0, 0, 0, "", taskType)
}
// CreateClusterRemoveTask 生成集群删除域名任务
func (this *DNSTaskDAO) CreateClusterRemoveTask(tx *dbs.Tx, clusterId int64, domainId int64, recordName string) error {
return this.CreateDNSTask(tx, clusterId, 0, 0, domainId, recordName, DNSTaskTypeClusterRemoveDomain)
} }
// CreateNodeTask 生成节点任务 // CreateNodeTask 生成节点任务
func (this *DNSTaskDAO) CreateNodeTask(tx *dbs.Tx, nodeId int64, taskType DNSTaskType) error { func (this *DNSTaskDAO) CreateNodeTask(tx *dbs.Tx, nodeId int64, taskType DNSTaskType) error {
return this.CreateDNSTask(tx, 0, 0, nodeId, 0, taskType) return this.CreateDNSTask(tx, 0, 0, nodeId, 0, "", taskType)
} }
// CreateServerTask 生成服务任务 // CreateServerTask 生成服务任务
func (this *DNSTaskDAO) CreateServerTask(tx *dbs.Tx, serverId int64, taskType DNSTaskType) error { func (this *DNSTaskDAO) CreateServerTask(tx *dbs.Tx, clusterId int64, serverId int64, taskType DNSTaskType) error {
return this.CreateDNSTask(tx, 0, serverId, 0, 0, taskType) return this.CreateDNSTask(tx, clusterId, serverId, 0, 0, "", taskType)
} }
// CreateDomainTask 生成域名更新任务 // CreateDomainTask 生成域名更新任务
func (this *DNSTaskDAO) CreateDomainTask(tx *dbs.Tx, domainId int64, taskType DNSTaskType) error { func (this *DNSTaskDAO) CreateDomainTask(tx *dbs.Tx, domainId int64, taskType DNSTaskType) error {
return this.CreateDNSTask(tx, 0, 0, 0, domainId, taskType) return this.CreateDNSTask(tx, 0, 0, 0, domainId, "", taskType)
} }
// FindAllDoingTasks 查找所有正在执行的任务 // FindAllDoingTasks 查找所有正在执行的任务
@@ -101,6 +108,7 @@ func (this *DNSTaskDAO) FindAllDoingOrErrorTasks(tx *dbs.Tx, nodeClusterId int64
} }
_, err = query. _, err = query.
Where("(isDone=0 OR (isDone=1 AND isOk=0))"). Where("(isDone=0 OR (isDone=1 AND isOk=0))").
Asc("updatedAt").
AscPk(). AscPk().
Slice(&result). Slice(&result).
FindAll() FindAll()

View File

@@ -1,30 +1,32 @@
package dns package dns
// DNS更新任务 // DNSTask DNS更新任务
type DNSTask struct { type DNSTask struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID ClusterId uint32 `field:"clusterId"` // 集群ID
ServerId uint32 `field:"serverId"` // 服务ID ServerId uint32 `field:"serverId"` // 服务ID
NodeId uint32 `field:"nodeId"` // 节点ID NodeId uint32 `field:"nodeId"` // 节点ID
DomainId uint32 `field:"domainId"` // 域名ID DomainId uint32 `field:"domainId"` // 域名ID
Type string `field:"type"` // 任务类型 RecordName string `field:"recordName"` // 记录名
UpdatedAt uint64 `field:"updatedAt"` // 更新时间 Type string `field:"type"` // 任务类型
IsDone uint8 `field:"isDone"` // 是否已完成 UpdatedAt uint64 `field:"updatedAt"` // 更新时间
IsOk uint8 `field:"isOk"` // 是否成 IsDone bool `field:"isDone"` // 是否已完
Error string `field:"error"` // 错误信息 IsOk bool `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息
} }
type DNSTaskOperator struct { type DNSTaskOperator struct {
Id interface{} // ID Id interface{} // ID
ClusterId interface{} // 集群ID ClusterId interface{} // 集群ID
ServerId interface{} // 服务ID ServerId interface{} // 服务ID
NodeId interface{} // 节点ID NodeId interface{} // 节点ID
DomainId interface{} // 域名ID DomainId interface{} // 域名ID
Type interface{} // 任务类型 RecordName interface{} // 记录名
UpdatedAt interface{} // 更新时间 Type interface{} // 任务类型
IsDone interface{} // 是否已完成 UpdatedAt interface{} // 更新时间
IsOk interface{} // 是否成 IsDone interface{} // 是否已完
Error interface{} // 错误信息 IsOk interface{} // 是否成功
Error interface{} // 错误信息
} }
func NewDNSTaskOperator() *DNSTaskOperator { func NewDNSTaskOperator() *DNSTaskOperator {

View File

@@ -153,7 +153,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster) (issues []*pb.DNSI
} }
// 检查IP地址 // 检查IP地址
ipAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, nodeconfigs.NodeRoleNode) ipAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, true, nodeconfigs.NodeRoleNode)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -4,7 +4,7 @@ package models
type FileChunk struct { type FileChunk struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
FileId uint32 `field:"fileId"` // 文件ID FileId uint32 `field:"fileId"` // 文件ID
Data string `field:"data"` // 分块内容 Data []byte `field:"data"` // 分块内容
} }
type FileChunkOperator struct { type FileChunkOperator struct {

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/utils"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -33,7 +34,7 @@ func init() {
}) })
} }
// 启用条目 // EnableFile 启用条目
func (this *FileDAO) EnableFile(tx *dbs.Tx, id int64) error { func (this *FileDAO) EnableFile(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -42,7 +43,7 @@ func (this *FileDAO) EnableFile(tx *dbs.Tx, id int64) error {
return err return err
} }
// 禁用条目 // DisableFile 禁用条目
func (this *FileDAO) DisableFile(tx *dbs.Tx, id int64) error { func (this *FileDAO) DisableFile(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -51,7 +52,7 @@ func (this *FileDAO) DisableFile(tx *dbs.Tx, id int64) error {
return err return err
} }
// 查找启用中的条目 // FindEnabledFile 查找启用中的条目
func (this *FileDAO) FindEnabledFile(tx *dbs.Tx, id int64) (*File, error) { func (this *FileDAO) FindEnabledFile(tx *dbs.Tx, id int64) (*File, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Pk(id).
@@ -63,9 +64,9 @@ func (this *FileDAO) FindEnabledFile(tx *dbs.Tx, id int64) (*File, error) {
return result.(*File), err return result.(*File), err
} }
// 创建文件 // CreateFile 创建文件
func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, businessType, description string, filename string, size int64, isPublic bool) (int64, error) { func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, businessType, description string, filename string, size int64, isPublic bool) (int64, error) {
op := NewFileOperator() var op = NewFileOperator()
op.AdminId = adminId op.AdminId = adminId
op.UserId = userId op.UserId = userId
op.Type = businessType op.Type = businessType
@@ -74,6 +75,7 @@ func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, busines
op.Size = size op.Size = size
op.Filename = filename op.Filename = filename
op.IsPublic = isPublic op.IsPublic = isPublic
op.Code = utils.Sha1RandomString()
err := this.Save(tx, op) err := this.Save(tx, op)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -82,7 +84,7 @@ func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, busines
return types.Int64(op.Id), nil return types.Int64(op.Id), nil
} }
// 将文件置为已完成 // UpdateFileIsFinished 将文件置为已完成
func (this *FileDAO) UpdateFileIsFinished(tx *dbs.Tx, fileId int64) error { func (this *FileDAO) UpdateFileIsFinished(tx *dbs.Tx, fileId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(fileId). Pk(fileId).

View File

@@ -1,9 +1,10 @@
package models package models
// 文件管理 // File 文件管理
type File struct { type File struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
Code string `field:"code"` // 代号
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
Description string `field:"description"` // 文件描述 Description string `field:"description"` // 文件描述
Filename string `field:"filename"` // 文件名 Filename string `field:"filename"` // 文件名
@@ -12,13 +13,14 @@ type File struct {
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
Type string `field:"type"` // 类型 Type string `field:"type"` // 类型
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
IsFinished uint8 `field:"isFinished"` // 是否已完成上传 IsFinished bool `field:"isFinished"` // 是否已完成上传
IsPublic uint8 `field:"isPublic"` // 是否可以公开访问 IsPublic bool `field:"isPublic"` // 是否可以公开访问
} }
type FileOperator struct { type FileOperator struct {
Id interface{} // ID Id interface{} // ID
AdminId interface{} // 管理员ID AdminId interface{} // 管理员ID
Code interface{} // 代号
UserId interface{} // 用户ID UserId interface{} // 用户ID
Description interface{} // 文件描述 Description interface{} // 文件描述
Filename interface{} // 文件名 Filename interface{} // 文件名

View File

@@ -3,6 +3,7 @@ package models
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -22,6 +23,7 @@ import (
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"net" "net"
"net/http" "net/http"
"net/url"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@@ -180,8 +182,8 @@ Loop:
// CreateHTTPAccessLog 写入单条访问日志 // CreateHTTPAccessLog 写入单条访问日志
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error { func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
var day = timeutil.Format("Ymd", time.Unix(accessLog.Timestamp, 0)) var day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
tableDef, err := SharedHTTPAccessLogManager.FindTable(dao.Instance, day, true) tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true)
if err != nil { if err != nil {
return err return err
} }
@@ -221,10 +223,26 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
Sets(fields). Sets(fields).
Insert() Insert()
if err != nil { if err != nil {
return err // 错误重试
if CheckSQLErrCode(err, 1146) { // Error 1146: Table 'xxx' doesn't exist
err = SharedHTTPAccessLogManager.CreateTable(dao.Instance, tableDef.Name)
if err != nil {
return err
}
// 重新尝试
lastId, err = dao.Query(tx).
Table(tableDef.Name).
Sets(fields).
Insert()
}
if err != nil {
return err
}
} }
if accessLogEnableAutoPartial && accessLogRowsPerTable > 0 && lastId%accessLogRowsPerTable == 0 { if accessLogEnableAutoPartial && accessLogRowsPerTable > 0 && lastId >= accessLogRowsPerTable {
SharedHTTPAccessLogManager.ResetTable(dao.Instance, day) SharedHTTPAccessLogManager.ResetTable(dao.Instance, day)
} }
@@ -232,7 +250,9 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
} }
// ListAccessLogs 读取往前的 单页访问日志 // ListAccessLogs 读取往前的 单页访问日志
func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string, func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx,
partition int32,
lastRequestId string,
size int64, size int64,
day string, day string,
hourFrom string, hourFrom string,
@@ -259,18 +279,19 @@ func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string,
size = 1000 size = 1000
} }
result, nextLastRequestId, err = this.listAccessLogs(tx, lastRequestId, size, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain) result, nextLastRequestId, err = this.listAccessLogs(tx, partition, lastRequestId, size, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
if err != nil || int64(len(result)) < size { if err != nil || int64(len(result)) < size {
return return
} }
moreResult, _, _ := this.listAccessLogs(tx, nextLastRequestId, 1, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain) moreResult, _, _ := this.listAccessLogs(tx, partition, nextLastRequestId, 1, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
hasMore = len(moreResult) > 0 hasMore = len(moreResult) > 0
return return
} }
// 读取往前的单页访问日志 // 读取往前的单页访问日志
func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
partition int32,
lastRequestId string, lastRequestId string,
size int64, size int64,
day string, day string,
@@ -293,7 +314,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
return nil, lastRequestId, nil return nil, lastRequestId, nil
} }
serverIds := []int64{} var serverIds = []int64{}
if userId > 0 { if userId > 0 {
serverIds, err = SharedServerDAO.FindAllEnabledServerIdsWithUserId(tx, userId) serverIds, err = SharedServerDAO.FindAllEnabledServerIdsWithUserId(tx, userId)
if err != nil { if err != nil {
@@ -305,7 +326,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
} }
accessLogLocker.RLock() accessLogLocker.RLock()
daoList := []*HTTPAccessLogDAOWrapper{} var daoList = []*HTTPAccessLogDAOWrapper{}
for _, daoWrapper := range httpAccessLogDAOMapping { for _, daoWrapper := range httpAccessLogDAOMapping {
daoList = append(daoList, daoWrapper) daoList = append(daoList, daoWrapper)
} }
@@ -323,7 +344,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
if clusterId > 0 { if clusterId > 0 {
nodeIds, err = SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId) nodeIds, err = SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId)
if err != nil { if err != nil {
remotelogs.Error("DBNODE", err.Error()) remotelogs.Error("DB_NODE", err.Error())
return return
} }
sort.Slice(nodeIds, func(i, j int) bool { sort.Slice(nodeIds, func(i, j int) bool {
@@ -333,32 +354,61 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
// 准备查询 // 准备查询
var tableQueries = []*accessLogTableQuery{} var tableQueries = []*accessLogTableQuery{}
var maxTableName = ""
for _, daoWrapper := range daoList { for _, daoWrapper := range daoList {
var instance = daoWrapper.DAO.Instance var instance = daoWrapper.DAO.Instance
tableDefs, err := SharedHTTPAccessLogManager.FindTables(instance, day) def, err := SharedHTTPAccessLogManager.FindPartitionTable(instance, day, partition)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
for _, def := range tableDefs { if !def.Exists {
tableQueries = append(tableQueries, &accessLogTableQuery{ continue
daoWrapper: daoWrapper,
name: def.Name,
hasRemoteAddrField: def.HasRemoteAddr,
hasDomainField: def.HasDomain,
})
} }
if len(maxTableName) == 0 || def.Name > maxTableName {
maxTableName = def.Name
}
tableQueries = append(tableQueries, &accessLogTableQuery{
daoWrapper: daoWrapper,
name: def.Name,
hasRemoteAddrField: def.HasRemoteAddr,
hasDomainField: def.HasDomain,
})
}
// 检查各个分表是否一致
if partition < 0 {
var newTableQueries = []*accessLogTableQuery{}
for _, tableQuery := range tableQueries {
if tableQuery.name != maxTableName {
continue
}
newTableQueries = append(newTableQueries, tableQuery)
}
tableQueries = newTableQueries
}
if len(tableQueries) == 0 {
return nil, "", nil
} }
var locker = sync.Mutex{} var locker = sync.Mutex{}
// 这里正则表达式中的括号不能轻易变更,因为后面有引用
// TODO 支持多个查询条件的组合,比如 status:200 proto:HTTP/1.1
var statusPrefixReg = regexp.MustCompile(`status:\s*(\d{3})\b`) var statusPrefixReg = regexp.MustCompile(`status:\s*(\d{3})\b`)
var statusRangeReg = regexp.MustCompile(`status:\s*(\d{3})-(\d{3})\b`) var statusRangeReg = regexp.MustCompile(`status:\s*(\d{3})-(\d{3})\b`)
var urlReg = regexp.MustCompile(`^(http|https)://`)
var requestPathReg = regexp.MustCompile(`requestPath:(\S+)`)
var protoReg = regexp.MustCompile(`proto:(\S+)`)
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
var count = len(tableQueries) var count = len(tableQueries)
var wg = &sync.WaitGroup{} var wg = &sync.WaitGroup{}
wg.Add(count) wg.Add(count)
for _, tableQuery := range tableQueries { for _, tableQuery := range tableQueries {
go func(tableQuery *accessLogTableQuery) { go func(tableQuery *accessLogTableQuery, keyword string) {
defer wg.Done() defer wg.Done()
var dao = tableQuery.daoWrapper.DAO var dao = tableQuery.daoWrapper.DAO
@@ -446,27 +496,53 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
} }
if len(keyword) > 0 { if len(keyword) > 0 {
// remoteAddr var isSpecialKeyword = false
if tableQuery.hasRemoteAddrField && net.ParseIP(keyword) != nil {
if tableQuery.hasRemoteAddrField && net.ParseIP(keyword) != nil { // ip
isSpecialKeyword = true
query.Attr("remoteAddr", keyword) query.Attr("remoteAddr", keyword)
} else if tableQuery.hasRemoteAddrField && regexp.MustCompile(`^ip:.+`).MatchString(keyword) { } else if tableQuery.hasRemoteAddrField && regexp.MustCompile(`^ip:.+`).MatchString(keyword) { // ip:x.x.x.x
isSpecialKeyword = true
keyword = keyword[3:] keyword = keyword[3:]
pieces := strings.SplitN(keyword, ",", 2) pieces := strings.SplitN(keyword, ",", 2)
if len(pieces) == 1 || len(pieces[1]) == 0 { if len(pieces) == 1 || len(pieces[1]) == 0 || pieces[0] == pieces[1] {
query.Attr("remoteAddr", pieces[0]) query.Attr("remoteAddr", pieces[0])
} else { } else {
query.Between("INET_ATON(remoteAddr)", utils.IP2Long(pieces[0]), utils.IP2Long(pieces[1])) query.Between("INET_ATON(remoteAddr)", utils.IP2Long(pieces[0]), utils.IP2Long(pieces[1]))
} }
} else if statusRangeReg.MatchString(keyword) { } else if statusRangeReg.MatchString(keyword) { // status:200-400
isSpecialKeyword = true
var matches = statusRangeReg.FindStringSubmatch(keyword) var matches = statusRangeReg.FindStringSubmatch(keyword)
query.Between("status", types.Int(matches[1]), types.Int(matches[2])) query.Between("status", types.Int(matches[1]), types.Int(matches[2]))
} else if statusPrefixReg.MatchString(keyword) { // status:200
// TODO 处理剩余的关键词 isSpecialKeyword = true
} else if statusPrefixReg.MatchString(keyword) {
var matches = statusPrefixReg.FindStringSubmatch(keyword) var matches = statusPrefixReg.FindStringSubmatch(keyword)
query.Attr("status", matches[1]) query.Attr("status", matches[1])
// TODO 处理剩余的关键词 } else if requestPathReg.MatchString(keyword) {
} else { isSpecialKeyword = true
var matches = requestPathReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.requestPath')=:keyword").
Param("keyword", matches[1])
} else if protoReg.MatchString(keyword) {
isSpecialKeyword = true
var matches = protoReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.proto')=:keyword").
Param("keyword", strings.ToUpper(matches[1]))
} else if schemeReg.MatchString(keyword) {
isSpecialKeyword = true
var matches = schemeReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.scheme')=:keyword").
Param("keyword", strings.ToLower(matches[1]))
} else if urlReg.MatchString(keyword) { // https://xxx/yyy
u, err := url.Parse(keyword)
if err == nil {
isSpecialKeyword = true
query.Attr("domain", u.Host)
query.Where("JSON_EXTRACT(content, '$.requestURI') LIKE :keyword").
Param("keyword", dbutils.QuoteLikePrefix("\""+u.RequestURI()))
}
}
if !isSpecialKeyword {
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) { if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
keyword = keyword[3:] keyword = keyword[3:]
} }
@@ -514,7 +590,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
} }
query.Where("("+where+")"). query.Where("("+where+")").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
if useOriginKeyword { if useOriginKeyword {
query.Param("originKeyword", keyword) query.Param("originKeyword", keyword)
} }
@@ -558,17 +634,17 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
Limit(size). Limit(size).
FindAll() FindAll()
if err != nil { if err != nil {
logs.Println("[DB_NODE]" + err.Error()) remotelogs.Println("DB_NODE", err.Error())
return return
} }
locker.Lock() locker.Lock()
for _, one := range ones { for _, one := range ones {
accessLog := one.(*HTTPAccessLog) var accessLog = one.(*HTTPAccessLog)
result = append(result, accessLog) result = append(result, accessLog)
} }
locker.Unlock() locker.Unlock()
}(tableQuery) }(tableQuery, keyword)
} }
wg.Wait() wg.Wait()

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
@@ -53,7 +54,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, -1, "", 10, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -80,7 +81,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page(t *testing.T) {
times := 0 // 防止循环次数太多 times := 0 // 防止循环次数太多
for { for {
before := time.Now() before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, -1, lastRequestId, 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds() cost := time.Since(before).Seconds()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -111,7 +112,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Reverse(t *testing.T) {
} }
before := time.Now() before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, true, false, 0, 0, 0, false, 0, "", "", "") accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, -1, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, true, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds() cost := time.Since(before).Seconds()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -136,7 +137,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page_NotExists(t *testing.T) {
times := 0 // 防止循环次数太多 times := 0 // 防止循环次数太多
for { for {
before := time.Now() before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, -1, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds() cost := time.Since(before).Seconds()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -157,3 +158,13 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page_NotExists(t *testing.T) {
} }
} }
} }
func BenchmarkHTTPAccessLogDAO_JSONEncode(b *testing.B) {
var accessLog = &pb.HTTPAccessLog{
RequestPath: "/hello/world",
}
for i := 0; i < b.N; i++ {
_, _ = json.Marshal(accessLog)
}
}

View File

@@ -5,7 +5,6 @@ package models
import ( import (
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
@@ -16,6 +15,7 @@ import (
) )
// 访问日志的两个表格形式 // 访问日志的两个表格形式
// 括号位置需要固定,会用来读取日期和分区
var accessLogTableMainReg = regexp.MustCompile(`_(\d{8})$`) var accessLogTableMainReg = regexp.MustCompile(`_(\d{8})$`)
var accessLogTablePartialReg = regexp.MustCompile(`_(\d{8})_(\d{4})$`) var accessLogTablePartialReg = regexp.MustCompile(`_(\d{8})_(\d{4})$`)
@@ -39,7 +39,7 @@ func (this *HTTPAccessLogManager) FindTableNames(db *dbs.DB, day string) ([]stri
// 需要防止用户设置了表名自动小写 // 需要防止用户设置了表名自动小写
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} { for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindOnes(`SHOW TABLES LIKE '` + prefix + `'`) ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil { if err != nil {
return nil, errors.New("query table names error: " + err.Error()) return nil, errors.New("query table names error: " + err.Error())
} }
@@ -60,7 +60,15 @@ func (this *HTTPAccessLogManager) FindTableNames(db *dbs.DB, day string) ([]stri
} }
// 排序 // 排序
sort.Strings(results) // 这里不能直接使用sort.Strings(),因为表名里面可能大小写混合
sort.Slice(results, func(i, j int) bool {
var name1 = results[i]
var name2 = results[j]
if len(name1) < len(name2) {
return true
}
return strings.ToLower(name1) < strings.ToLower(name2)
})
return results, nil return results, nil
} }
@@ -70,9 +78,15 @@ func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAcc
var results = []*httpAccessLogDefinition{} var results = []*httpAccessLogDefinition{}
var tableNames = []string{} var tableNames = []string{}
config, err := db.Config()
if err != nil {
return nil, err
}
var cachePrefix = config.Dsn
// 需要防止用户设置了表名自动小写 // 需要防止用户设置了表名自动小写
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} { for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindOnes(`SHOW TABLES LIKE '` + prefix + `'`) ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil { if err != nil {
return nil, errors.New("query table names error: " + err.Error()) return nil, errors.New("query table names error: " + err.Error())
} }
@@ -89,17 +103,32 @@ func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAcc
if accessLogTableMainReg.MatchString(tableName) { if accessLogTableMainReg.MatchString(tableName) {
tableNames = append(tableNames, tableName) tableNames = append(tableNames, tableName)
hasRemoteAddrField, hasDomainField, err := this.checkTableFields(db, tableName) // 查找已有的表格信息避免SHOW FIELDS
if err != nil { var tableDay = tableName[strings.LastIndex(tableName, "_")+1:]
return nil, err var cacheKey = this.composeTableCacheKey(cachePrefix, tableDay)
} this.locker.Lock()
currentTableDef, ok := this.currentTableMapping[cacheKey]
this.locker.Unlock()
if ok {
results = append(results, &httpAccessLogDefinition{
Name: tableName,
HasRemoteAddr: currentTableDef.HasRemoteAddr,
HasDomain: currentTableDef.HasDomain,
Exists: true,
})
} else {
hasRemoteAddrField, hasDomainField, err := this.checkTableFields(db, tableName)
if err != nil {
return nil, err
}
results = append(results, &httpAccessLogDefinition{ results = append(results, &httpAccessLogDefinition{
Name: tableName, Name: tableName,
HasRemoteAddr: hasRemoteAddrField, HasRemoteAddr: hasRemoteAddrField,
HasDomain: hasDomainField, HasDomain: hasDomainField,
Exists: true, Exists: true,
}) })
}
} else if accessLogTablePartialReg.MatchString(tableName) { } else if accessLogTablePartialReg.MatchString(tableName) {
tableNames = append(tableNames, tableName) tableNames = append(tableNames, tableName)
@@ -121,11 +150,55 @@ func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAcc
return results, nil return results, nil
} }
// FindTable 根据日期获取表名 func (this *HTTPAccessLogManager) FindPartitionTable(db *dbs.DB, day string, partition int32) (*httpAccessLogDefinition, error) {
var tableNames []string
if partition < 0 {
tableList, err := this.FindTables(db, day)
if err != nil {
return nil, err
}
if len(tableList) > 0 {
return tableList[len(tableList)-1], nil
}
return &httpAccessLogDefinition{
Name: "",
HasRemoteAddr: false,
HasDomain: false,
Exists: false,
}, nil
} else if partition == 0 {
tableNames = []string{"edgeHTTPAccessLogs_" + day, "edgehttpaccesslogs_" + day}
} else {
tableNames = []string{"edgeHTTPAccessLogs_" + day + "_" + fmt.Sprintf("%04d", partition), "edgehttpaccesslogs_" + day + "_" + fmt.Sprintf("%04d", partition)}
}
for _, tableName := range tableNames {
hasRemoteField, hasDomainField, err := this.checkTableFields(db, tableName)
if err != nil {
continue
}
return &httpAccessLogDefinition{
Name: tableName,
HasRemoteAddr: hasRemoteField,
HasDomain: hasDomainField,
Exists: true,
}, nil
}
return &httpAccessLogDefinition{
Name: "",
HasRemoteAddr: false,
HasDomain: false,
Exists: false,
}, nil
}
// FindLastTable 根据日期获取上一个可以使用的表名
// 表名组成 // 表名组成
// - PREFIX_DAY // - PREFIX_DAY
// - PREFIX_DAY_0001 // - PREFIX_DAY_0001
func (this *HTTPAccessLogManager) FindTable(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) { func (this *HTTPAccessLogManager) FindLastTable(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) {
this.locker.Lock() this.locker.Lock()
defer this.locker.Unlock() defer this.locker.Unlock()
@@ -133,7 +206,8 @@ func (this *HTTPAccessLogManager) FindTable(db *dbs.DB, day string, force bool)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var cacheKey = config.Dsn var cachePrefix = config.Dsn
var cacheKey = this.composeTableCacheKey(cachePrefix, day)
def, ok := this.currentTableMapping[cacheKey] def, ok := this.currentTableMapping[cacheKey]
if ok { if ok {
return def, nil return def, nil
@@ -144,7 +218,22 @@ func (this *HTTPAccessLogManager) FindTable(db *dbs.DB, day string, force bool)
return nil, err return nil, err
} }
this.currentTableMapping[cacheKey] = def // 只有存在的表格才缓存
if def != nil && def.Exists {
this.currentTableMapping[cacheKey] = def
// 清除过时缓存
for oldCacheKey := range this.currentTableMapping {
var dayIndex = strings.LastIndex(oldCacheKey, "_")
if dayIndex > 0 {
var oldPrefix = oldCacheKey[:dayIndex]
var oldDay = oldCacheKey[dayIndex+1:]
if oldPrefix == cachePrefix && oldDay < day {
delete(this.currentTableMapping, oldCacheKey)
}
}
}
}
return def, nil return def, nil
} }
@@ -152,14 +241,7 @@ func (this *HTTPAccessLogManager) FindTable(db *dbs.DB, day string, force bool)
func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error { func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error {
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';") _, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
if err != nil { if err != nil {
// 快速判断错误方法 if CheckSQLErrCode(err, 1050) { // Error 1050: Table 'xxx' already exists
mysqlErr, ok := err.(*mysql.MySQLError)
if ok && mysqlErr.Number == 1050 { // Error 1050: Table 'xxx' already exists
return nil
}
// 防止二次包装过程中错误丢失的保底错误判断方法
if strings.Contains(err.Error(), "Error 1050") {
return nil return nil
} }
@@ -178,7 +260,61 @@ func (this *HTTPAccessLogManager) ResetTable(db *dbs.DB, day string) {
if err != nil { if err != nil {
return return
} }
delete(this.currentTableMapping, config.Dsn) delete(this.currentTableMapping, this.composeTableCacheKey(config.Dsn, day))
}
// TablePartition 从表名中获取分区
func (this *HTTPAccessLogManager) TablePartition(tableName string) (partition int32) {
if accessLogTablePartialReg.MatchString(tableName) {
return types.Int32(accessLogTablePartialReg.FindStringSubmatch(tableName)[2])
}
return 0
}
// FindLatestPartition 读取最后一个分区
func (this *HTTPAccessLogManager) FindLatestPartition(day string) (int32, error) {
var dbList = AllAccessLogDBs()
if len(dbList) == 0 {
return 0, errors.New("no valid database")
}
var partitions = []int32{}
var locker sync.Mutex
var wg = sync.WaitGroup{}
wg.Add(len(dbList))
var lastErr error
for _, db := range dbList {
go func(db *dbs.DB) {
defer wg.Done()
names, err := this.FindTableNames(db, day)
if err != nil {
lastErr = err
}
for _, name := range names {
var partition = this.TablePartition(name)
locker.Lock()
if !lists.Contains(partitions, partition) {
partitions = append(partitions, partition)
}
locker.Unlock()
}
}(db)
}
wg.Wait()
if lastErr != nil {
return 0, lastErr
}
if len(partitions) == 0 {
return 0, nil
}
return partitions[len(partitions)-1], nil
} }
// 查找某个表格 // 查找某个表格
@@ -280,7 +416,7 @@ func (this *HTTPAccessLogManager) findTableWithoutCache(db *dbs.DB, day string,
// TODO 考虑缓存检查结果 // TODO 考虑缓存检查结果
func (this *HTTPAccessLogManager) checkTableFields(db *dbs.DB, tableName string) (hasRemoteAddrField bool, hasDomainField bool, err error) { func (this *HTTPAccessLogManager) checkTableFields(db *dbs.DB, tableName string) (hasRemoteAddrField bool, hasDomainField bool, err error) {
fields, _, err := db.FindOnes("SHOW FIELDS FROM " + tableName) fields, _, err := db.FindPreparedOnes("SHOW FIELDS FROM " + tableName)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }
@@ -295,3 +431,9 @@ func (this *HTTPAccessLogManager) checkTableFields(db *dbs.DB, tableName string)
} }
return return
} }
// 组合表格的缓存Key
func (this *HTTPAccessLogManager) composeTableCacheKey(dsn string, day string) string {
// 注意:格式一定要固定,下面清除缓存的时候需要用到
return dsn + "_" + day
}

View File

@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing" "testing"
"time" "time"
) )
@@ -30,6 +31,9 @@ func TestNewHTTPAccessLogManager(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer func() {
_ = db.Close()
}()
var manager = models.SharedHTTPAccessLogManager var manager = models.SharedHTTPAccessLogManager
err = manager.CreateTable(db, "accessLog_1") err = manager.CreateTable(db, "accessLog_1")
@@ -58,6 +62,9 @@ func TestHTTPAccessLogManager_FindTableNames(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer func() {
_ = db.Close()
}()
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
var before = time.Now() var before = time.Now()
@@ -74,7 +81,6 @@ func TestHTTPAccessLogManager_FindTableNames(t *testing.T) {
} }
} }
func TestHTTPAccessLogManager_FindTables(t *testing.T) { func TestHTTPAccessLogManager_FindTables(t *testing.T) {
var config = &dbs.DBConfig{ var config = &dbs.DBConfig{
Driver: "mysql", Driver: "mysql",
@@ -95,6 +101,9 @@ func TestHTTPAccessLogManager_FindTables(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer func() {
_ = db.Close()
}()
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
var before = time.Now() var before = time.Now()
@@ -111,7 +120,7 @@ func TestHTTPAccessLogManager_FindTables(t *testing.T) {
} }
} }
func TestHTTPAccessLogManager_FindTable(t *testing.T) { func TestHTTPAccessLogManager_FindLastTable(t *testing.T) {
var config = &dbs.DBConfig{ var config = &dbs.DBConfig{
Driver: "mysql", Driver: "mysql",
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s", Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
@@ -131,10 +140,13 @@ func TestHTTPAccessLogManager_FindTable(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer func() {
_ = db.Close()
}()
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
var before = time.Now() var before = time.Now()
tableDef, err := models.SharedHTTPAccessLogManager.FindTable(db, "20220306", false) tableDef, err := models.SharedHTTPAccessLogManager.FindLastTable(db, "20220306", false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -146,3 +158,32 @@ func TestHTTPAccessLogManager_FindTable(t *testing.T) {
t.Log(time.Since(before).Seconds()*1000, "ms") t.Log(time.Since(before).Seconds()*1000, "ms")
} }
} }
func TestHTTPAccessLogManager_FindPartitionTable(t *testing.T) {
var config = &dbs.DBConfig{
Driver: "mysql",
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
Prefix: "edge",
Connections: struct {
Pool int `yaml:"pool"`
Max int `yaml:"max"`
Life string `yaml:"life"`
LifeDuration time.Duration `yaml:",omitempty"`
}{},
Models: struct {
Package string `yaml:"package"`
}{},
}
db, err := dbs.NewInstanceFromConfig(config)
if err != nil {
t.Fatal(err)
}
defer func() {
_ = db.Close()
}()
t.Log(models.SharedHTTPAccessLogManager.FindPartitionTable(db, timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)), -1))
t.Log(models.SharedHTTPAccessLogManager.FindPartitionTable(db, timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)), 0))
t.Log(models.SharedHTTPAccessLogManager.FindPartitionTable(db, timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)), 1))
}

View File

@@ -1,22 +1,24 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPAccessLog 访问日志 // HTTPAccessLog 访问日志
type HTTPAccessLog struct { type HTTPAccessLog struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
ServerId uint32 `field:"serverId"` // 服务ID ServerId uint32 `field:"serverId"` // 服务ID
NodeId uint32 `field:"nodeId"` // 节点ID NodeId uint32 `field:"nodeId"` // 节点ID
Status uint32 `field:"status"` // 状态码 Status uint32 `field:"status"` // 状态码
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Content string `field:"content"` // 日志内容 Content dbs.JSON `field:"content"` // 日志内容
RequestId string `field:"requestId"` // 请求ID RequestId string `field:"requestId"` // 请求ID
FirewallPolicyId uint32 `field:"firewallPolicyId"` // WAF策略ID FirewallPolicyId uint32 `field:"firewallPolicyId"` // WAF策略ID
FirewallRuleGroupId uint32 `field:"firewallRuleGroupId"` // WAF分组ID FirewallRuleGroupId uint32 `field:"firewallRuleGroupId"` // WAF分组ID
FirewallRuleSetId uint32 `field:"firewallRuleSetId"` // WAF集ID FirewallRuleSetId uint32 `field:"firewallRuleSetId"` // WAF集ID
FirewallRuleId uint32 `field:"firewallRuleId"` // WAF规则ID FirewallRuleId uint32 `field:"firewallRuleId"` // WAF规则ID
RemoteAddr string `field:"remoteAddr"` // IP地址 RemoteAddr string `field:"remoteAddr"` // IP地址
Domain string `field:"domain"` // 域名 Domain string `field:"domain"` // 域名
RequestBody string `field:"requestBody"` // 请求内容 RequestBody []byte `field:"requestBody"` // 请求内容
ResponseBody string `field:"responseBody"` // 响应内容 ResponseBody []byte `field:"responseBody"` // 响应内容
} }
type HTTPAccessLogOperator struct { type HTTPAccessLogOperator struct {

View File

@@ -8,11 +8,11 @@ import (
// ToPB 转换成PB对象 // ToPB 转换成PB对象
func (this *HTTPAccessLog) ToPB() (*pb.HTTPAccessLog, error) { func (this *HTTPAccessLog) ToPB() (*pb.HTTPAccessLog, error) {
p := &pb.HTTPAccessLog{} p := &pb.HTTPAccessLog{}
err := json.Unmarshal([]byte(this.Content), p) err := json.Unmarshal(this.Content, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
p.RequestId = this.RequestId p.RequestId = this.RequestId
p.RequestBody = []byte(this.RequestBody) p.RequestBody = this.RequestBody
return p, nil return p, nil
} }

View File

@@ -1,13 +1,10 @@
package models package models
import ( import (
"bytes"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
) )
const ( const (
@@ -109,7 +106,7 @@ func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAndOnPolicies(tx *dbs.Tx) (res
} }
// CreatePolicy 创建策略 // CreatePolicy 创建策略
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool) (policyId int64, err error) { func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool) (policyId int64, err error) {
var op = NewHTTPAccessLogPolicyOperator() var op = NewHTTPAccessLogPolicyOperator()
op.Name = name op.Name = name
op.Type = policyType op.Type = policyType
@@ -121,12 +118,13 @@ func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policy
} }
op.IsPublic = isPublic op.IsPublic = isPublic
op.IsOn = true op.IsOn = true
op.FirewallOnly = firewallOnly
op.State = HTTPAccessLogPolicyStateEnabled op.State = HTTPAccessLogPolicyStateEnabled
return this.SaveInt64(tx, op) return this.SaveInt64(tx, op)
} }
// UpdatePolicy 修改策略 // UpdatePolicy 修改策略
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, isOn bool) error { func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, isOn bool) error {
if policyId <= 0 { if policyId <= 0 {
return errors.New("invalid policyId") return errors.New("invalid policyId")
} }
@@ -140,7 +138,6 @@ func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, nam
if oldOne == nil { if oldOne == nil {
return nil return nil
} }
var oldPolicy = oldOne.(*HTTPAccessLogPolicy)
var op = NewHTTPAccessLogPolicyOperator() var op = NewHTTPAccessLogPolicyOperator()
op.Id = policyId op.Id = policyId
@@ -156,22 +153,11 @@ func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, nam
op.Conds = "{}" op.Conds = "{}"
} }
// 版本号 // 版本号总是加1
if len(oldPolicy.Options) == 0 || len(optionsJSON) == 0 { op.Version = dbs.SQL("version+1")
op.Version = dbs.SQL("version+1")
} else {
var m1 = maps.Map{}
_ = json.Unmarshal([]byte(oldPolicy.Options), &m1)
var m2 = maps.Map{}
_ = json.Unmarshal(optionsJSON, &m2)
if bytes.Compare(m1.AsJSON(), m2.AsJSON()) != 0 {
op.Version = dbs.SQL("version+1")
}
}
op.IsPublic = isPublic op.IsPublic = isPublic
op.FirewallOnly = firewallOnly
op.IsOn = isOn op.IsOn = isOn
return this.Save(tx, op) return this.Save(tx, op)
} }

View File

@@ -1,36 +1,40 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPAccessLogPolicy 访问日志策略 // HTTPAccessLogPolicy 访问日志策略
type HTTPAccessLogPolicy struct { type HTTPAccessLogPolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Type string `field:"type"` // 存储类型 Type string `field:"type"` // 存储类型
Options string `field:"options"` // 存储选项 Options dbs.JSON `field:"options"` // 存储选项
Conds string `field:"conds"` // 请求条件 Conds dbs.JSON `field:"conds"` // 请求条件
IsPublic uint8 `field:"isPublic"` // 是否为公用 IsPublic bool `field:"isPublic"` // 是否为公用
Version uint32 `field:"version"` // 版本号 FirewallOnly uint8 `field:"firewallOnly"` // 是否只记录防火墙相关
Version uint32 `field:"version"` // 版本号
} }
type HTTPAccessLogPolicyOperator struct { type HTTPAccessLogPolicyOperator struct {
Id interface{} // ID Id interface{} // ID
TemplateId interface{} // 模版ID TemplateId interface{} // 模版ID
AdminId interface{} // 管理员ID AdminId interface{} // 管理员ID
UserId interface{} // 用户ID UserId interface{} // 用户ID
State interface{} // 状态 State interface{} // 状态
CreatedAt interface{} // 创建时间 CreatedAt interface{} // 创建时间
Name interface{} // 名称 Name interface{} // 名称
IsOn interface{} // 是否启用 IsOn interface{} // 是否启用
Type interface{} // 存储类型 Type interface{} // 存储类型
Options interface{} // 存储选项 Options interface{} // 存储选项
Conds interface{} // 请求条件 Conds interface{} // 请求条件
IsPublic interface{} // 是否为公用 IsPublic interface{} // 是否为公用
Version interface{} // 版本号 FirewallOnly interface{} // 是否只记录防火墙相关
Version interface{} // 版本号
} }
func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator { func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator {

View File

@@ -116,13 +116,13 @@ func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, c
var config = &serverconfigs.HTTPAuthPolicy{ var config = &serverconfigs.HTTPAuthPolicy{
Id: int64(policy.Id), Id: int64(policy.Id),
Name: policy.Name, Name: policy.Name,
IsOn: policy.IsOn == 1, IsOn: policy.IsOn,
Type: policy.Type, Type: policy.Type,
} }
var params map[string]interface{} var params map[string]interface{}
if IsNotNull(policy.Params) { if IsNotNull(policy.Params) {
err = json.Unmarshal([]byte(policy.Params), &params) err = json.Unmarshal(policy.Params, &params)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,15 +1,17 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPAuthPolicy HTTP认证策略 // HTTPAuthPolicy HTTP认证策略
type HTTPAuthPolicy struct { type HTTPAuthPolicy struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Type string `field:"type"` // 类型 Type string `field:"type"` // 类型
Params string `field:"params"` // 参数 Params dbs.JSON `field:"params"` // 参数
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
type HTTPAuthPolicyOperator struct { type HTTPAuthPolicyOperator struct {

View File

@@ -80,10 +80,10 @@ func (this *HTTPBrotliPolicyDAO) ComposeBrotliConfig(tx *dbs.Tx, policyId int64)
config := &serverconfigs.HTTPBrotliCompressionConfig{} config := &serverconfigs.HTTPBrotliCompressionConfig{}
config.Id = int64(policy.Id) config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1 config.IsOn = policy.IsOn
if IsNotNull(policy.MinLength) { if IsNotNull(policy.MinLength) {
minLengthConfig := &shared.SizeCapacity{} minLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.MinLength), minLengthConfig) err = json.Unmarshal(policy.MinLength, minLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -91,7 +91,7 @@ func (this *HTTPBrotliPolicyDAO) ComposeBrotliConfig(tx *dbs.Tx, policyId int64)
} }
if IsNotNull(policy.MaxLength) { if IsNotNull(policy.MaxLength) {
maxLengthConfig := &shared.SizeCapacity{} maxLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.MaxLength), maxLengthConfig) err = json.Unmarshal(policy.MaxLength, maxLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -101,7 +101,7 @@ func (this *HTTPBrotliPolicyDAO) ComposeBrotliConfig(tx *dbs.Tx, policyId int64)
if IsNotNull(policy.Conds) { if IsNotNull(policy.Conds) {
condsConfig := &shared.HTTPRequestCondsConfig{} condsConfig := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(policy.Conds), condsConfig) err = json.Unmarshal(policy.Conds, condsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,17 +1,19 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPBrotliPolicy Gzip配置 // HTTPBrotliPolicy Gzip配置
type HTTPBrotliPolicy struct { type HTTPBrotliPolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Level uint32 `field:"level"` // 压缩级别 Level uint32 `field:"level"` // 压缩级别
MinLength string `field:"minLength"` // 可压缩最小值 MinLength dbs.JSON `field:"minLength"` // 可压缩最小值
MaxLength string `field:"maxLength"` // 可压缩最大值 MaxLength dbs.JSON `field:"maxLength"` // 可压缩最大值
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Conds string `field:"conds"` // 条件 Conds dbs.JSON `field:"conds"` // 条件
} }
type HTTPBrotliPolicyOperator struct { type HTTPBrotliPolicyOperator struct {

View File

@@ -2,6 +2,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
@@ -252,7 +253,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
} }
config := &serverconfigs.HTTPCachePolicy{} config := &serverconfigs.HTTPCachePolicy{}
config.Id = int64(policy.Id) config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1 config.IsOn = policy.IsOn
config.Name = policy.Name config.Name = policy.Name
config.Description = policy.Description config.Description = policy.Description
config.SyncCompressionCache = policy.SyncCompressionCache == 1 config.SyncCompressionCache = policy.SyncCompressionCache == 1
@@ -260,7 +261,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// capacity // capacity
if IsNotNull(policy.Capacity) { if IsNotNull(policy.Capacity) {
capacityConfig := &shared.SizeCapacity{} capacityConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.Capacity), capacityConfig) err = json.Unmarshal(policy.Capacity, capacityConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -272,7 +273,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// max size // max size
if IsNotNull(policy.MaxSize) { if IsNotNull(policy.MaxSize) {
maxSizeConfig := &shared.SizeCapacity{} maxSizeConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.MaxSize), maxSizeConfig) err = json.Unmarshal(policy.MaxSize, maxSizeConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -284,7 +285,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// options // options
if IsNotNull(policy.Options) { if IsNotNull(policy.Options) {
m := map[string]interface{}{} m := map[string]interface{}{}
err = json.Unmarshal([]byte(policy.Options), &m) err = json.Unmarshal(policy.Options, &m)
if err != nil { if err != nil {
return nil, errors.Wrap(err) return nil, errors.Wrap(err)
} }
@@ -294,7 +295,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// refs // refs
if IsNotNull(policy.Refs) { if IsNotNull(policy.Refs) {
refs := []*serverconfigs.HTTPCacheRef{} refs := []*serverconfigs.HTTPCacheRef{}
err = json.Unmarshal([]byte(policy.Refs), &refs) err = json.Unmarshal(policy.Refs, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -318,7 +319,7 @@ func (this *HTTPCachePolicyDAO) CountAllEnabledHTTPCachePolicies(tx *dbs.Tx, clu
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(storageType) > 0 { if len(storageType) > 0 {
query.Attr("type", storageType) query.Attr("type", storageType)
@@ -336,7 +337,7 @@ func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, cluster
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(storageType) > 0 { if len(storageType) > 0 {
query.Attr("type", storageType) query.Attr("type", storageType)

View File

@@ -1,23 +1,25 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPCachePolicy HTTP缓存策略 // HTTPCachePolicy HTTP缓存策略
type HTTPCachePolicy struct { type HTTPCachePolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Capacity string `field:"capacity"` // 容量数据 Capacity dbs.JSON `field:"capacity"` // 容量数据
MaxKeys uint64 `field:"maxKeys"` // 最多Key值 MaxKeys uint64 `field:"maxKeys"` // 最多Key值
MaxSize string `field:"maxSize"` // 最大缓存内容尺寸 MaxSize dbs.JSON `field:"maxSize"` // 最大缓存内容尺寸
Type string `field:"type"` // 存储类型 Type string `field:"type"` // 存储类型
Options string `field:"options"` // 存储选项 Options dbs.JSON `field:"options"` // 存储选项
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Refs string `field:"refs"` // 默认的缓存设置 Refs dbs.JSON `field:"refs"` // 默认的缓存设置
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存 SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
} }
type HTTPCachePolicyOperator struct { type HTTPCachePolicyOperator struct {

View File

@@ -0,0 +1,254 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
const (
HTTPCacheTaskStateEnabled = 1 // 已启用
HTTPCacheTaskStateDisabled = 0 // 已禁用
)
type HTTPCacheTaskType = string
const (
HTTPCacheTaskTypePurge HTTPCacheTaskType = "purge"
HTTPCacheTaskTypeFetch HTTPCacheTaskType = "fetch"
)
type HTTPCacheTaskDAO dbs.DAO
func init() {
dbs.OnReadyDone(func() {
// 清理数据任务
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedHTTPCacheTaskDAO.Clean(nil, 30) // 只保留N天
if err != nil {
remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error())
}
}
})
})
}
func NewHTTPCacheTaskDAO() *HTTPCacheTaskDAO {
return dbs.NewDAO(&HTTPCacheTaskDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeHTTPCacheTasks",
Model: new(HTTPCacheTask),
PkName: "id",
},
}).(*HTTPCacheTaskDAO)
}
var SharedHTTPCacheTaskDAO *HTTPCacheTaskDAO
func init() {
dbs.OnReady(func() {
SharedHTTPCacheTaskDAO = NewHTTPCacheTaskDAO()
})
}
// EnableHTTPCacheTask 启用条目
func (this *HTTPCacheTaskDAO) EnableHTTPCacheTask(tx *dbs.Tx, taskId int64) error {
_, err := this.Query(tx).
Pk(taskId).
Set("state", HTTPCacheTaskStateEnabled).
Update()
return err
}
// DisableHTTPCacheTask 禁用条目
func (this *HTTPCacheTaskDAO) DisableHTTPCacheTask(tx *dbs.Tx, taskId int64) error {
_, err := this.Query(tx).
Pk(taskId).
Set("state", HTTPCacheTaskStateDisabled).
Update()
if err != nil {
return err
}
return this.NotifyChange(tx, taskId)
}
// FindEnabledHTTPCacheTask 查找启用中的条目
func (this *HTTPCacheTaskDAO) FindEnabledHTTPCacheTask(tx *dbs.Tx, taskId int64) (*HTTPCacheTask, error) {
result, err := this.Query(tx).
Pk(taskId).
Attr("state", HTTPCacheTaskStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*HTTPCacheTask), err
}
// CreateTask 创建任务
func (this *HTTPCacheTaskDAO) CreateTask(tx *dbs.Tx, userId int64, taskType HTTPCacheTaskType, keyType string, description string) (int64, error) {
var op = NewHTTPCacheTaskOperator()
op.UserId = userId
op.Type = taskType
op.KeyType = keyType
op.IsOk = false
op.IsDone = false
op.IsReady = false
op.Description = description
op.Day = timeutil.Format("Ymd")
op.State = HTTPCacheTaskStateEnabled
taskId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.NotifyChange(tx, taskId)
if err != nil {
return 0, err
}
return taskId, nil
}
// ResetTask 重置服务状态
func (this *HTTPCacheTaskDAO) ResetTask(tx *dbs.Tx, taskId int64) error {
if taskId <= 0 {
return errors.New("invalid 'taskId'")
}
var op = NewHTTPCacheTaskOperator()
op.Id = taskId
op.IsOk = false
op.IsDone = false
op.DoneAt = 0
return this.Save(tx, op)
}
// UpdateTaskReady 设置任务为已准备
func (this *HTTPCacheTaskDAO) UpdateTaskReady(tx *dbs.Tx, taskId int64) error {
return this.Query(tx).
Pk(taskId).
Set("isReady", true).
UpdateQuickly()
}
// CountTasks 查询所有任务数量
func (this *HTTPCacheTaskDAO) CountTasks(tx *dbs.Tx, userId int64) (int64, error) {
var query = this.Query(tx).
State(HTTPCacheTaskStateEnabled).
Attr("isReady", true)
if userId > 0 {
query.Attr("userId", userId)
}
return query.Count()
}
// CountDoingTasks 查询正在执行的任务数量
func (this *HTTPCacheTaskDAO) CountDoingTasks(tx *dbs.Tx, userId int64) (int64, error) {
var query = this.Query(tx).
State(HTTPCacheTaskStateEnabled).
Attr("isReady", true).
Attr("isDone", false)
if userId > 0 {
query.Attr("userId", userId)
}
return query.Count()
}
// ListTasks 列出单页任务
func (this *HTTPCacheTaskDAO) ListTasks(tx *dbs.Tx, userId int64, offset int64, size int64) (result []*HTTPCacheTask, err error) {
var query = this.Query(tx).
State(HTTPCacheTaskStateEnabled).
Attr("isReady", true)
if userId > 0 {
query.Attr("userId", userId)
}
_, err = query.
Offset(offset).
Limit(size).
Slice(&result).
DescPk().
FindAll()
return
}
// ListDoingTasks 列出需要执行的任务
func (this *HTTPCacheTaskDAO) ListDoingTasks(tx *dbs.Tx, size int64) (result []*HTTPCacheTask, err error) {
_, err = this.Query(tx).
State(HTTPCacheTaskStateEnabled).
Attr("isDone", false).
Attr("isReady", true).
Limit(size).
AscPk(). // 按照先创建先执行的原则
Slice(&result).
FindAll()
return
}
// UpdateTaskStatus 标记任务已完成
func (this *HTTPCacheTaskDAO) UpdateTaskStatus(tx *dbs.Tx, taskId int64, isDone bool, isOk bool) error {
if taskId <= 0 {
return errors.New("invalid taskId '" + types.String(taskId) + "'")
}
var op = NewHTTPCacheTaskOperator()
op.Id = taskId
op.IsDone = isDone
op.IsOk = isOk
if isDone {
op.DoneAt = time.Now().Unix()
}
return this.Save(tx, op)
}
// CheckUserTask 检查用户任务
func (this *HTTPCacheTaskDAO) CheckUserTask(tx *dbs.Tx, userId int64, taskId int64) error {
b, err := this.Query(tx).
Pk(taskId).
Attr("userId", userId).
State(HTTPCacheTaskStateEnabled).
Exist()
if err != nil {
return err
}
if !b {
return ErrNotFound
}
return nil
}
// Clean 清理以往的任务
func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
// 删除Key
err := SharedHTTPCacheTaskKeyDAO.Clean(tx, days)
if err != nil {
return err
}
// 删除任务
_, err = this.Query(tx).
Lte("day", day).
Delete()
return err
}
// NotifyChange 发送通知
func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error {
// TODO
return nil
}

View File

@@ -0,0 +1,19 @@
package models_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestHTTPCacheTaskDAO_Clean(t *testing.T) {
dbs.NotifyReady()
err := models.SharedHTTPCacheTaskDAO.Clean(nil, 30)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -0,0 +1,218 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "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"
"time"
)
type HTTPCacheTaskKeyDAO dbs.DAO
func NewHTTPCacheTaskKeyDAO() *HTTPCacheTaskKeyDAO {
return dbs.NewDAO(&HTTPCacheTaskKeyDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeHTTPCacheTaskKeys",
Model: new(HTTPCacheTaskKey),
PkName: "id",
},
}).(*HTTPCacheTaskKeyDAO)
}
var SharedHTTPCacheTaskKeyDAO *HTTPCacheTaskKeyDAO
func init() {
dbs.OnReady(func() {
SharedHTTPCacheTaskKeyDAO = NewHTTPCacheTaskKeyDAO()
})
}
// CreateKey 创建Key
// 参数:
// - clusterId 集群ID
// - nodeMapJSON 集群下节点映射,格式类似于 `{ "节点1":true, ... }`
func (this *HTTPCacheTaskKeyDAO) CreateKey(tx *dbs.Tx, taskId int64, key string, taskType HTTPCacheTaskType, keyType string, clusterId int64) (int64, error) {
var op = NewHTTPCacheTaskKeyOperator()
op.TaskId = taskId
op.Key = key
op.Type = taskType
op.KeyType = keyType
op.ClusterId = clusterId
op.Nodes = "{}"
op.Errors = "{}"
return this.SaveInt64(tx, op)
}
// UpdateKeyStatus 修改Key状态
func (this *HTTPCacheTaskKeyDAO) UpdateKeyStatus(tx *dbs.Tx, keyId int64, nodeId int64, errString string, nodesJSON []byte) error {
if keyId <= 0 {
return errors.New("invalid 'keyId'")
}
if len(nodesJSON) == 0 {
nodesJSON = []byte("{}")
}
taskId, err := this.Query(tx).
Pk(keyId).
Result("taskId").
FindInt64Col(0)
if err != nil {
return err
}
var jsonPath = "$.\"" + types.String(nodeId) + "\""
var query = this.Query(tx).
Pk(keyId).
Set("nodes", dbs.SQL("JSON_SET(nodes, :jsonPath1, true)")).
Param("jsonPath1", jsonPath)
if len(errString) > 0 {
query.Set("errors", dbs.SQL("JSON_SET(errors, :jsonPath2, :jsonValue2)")).
Param("jsonPath2", jsonPath).
Param("jsonValue2", errString)
} else {
query.Set("errors", dbs.SQL("JSON_REMOVE(errors, :jsonPath2)")).
Param("jsonPath2", jsonPath)
}
err = query.
UpdateQuickly()
if err != nil {
return err
}
// 检查是否已完成
isDone, err := this.Query(tx).
Pk(keyId).
Where("JSON_CONTAINS(nodes, :nodesJSON)").
Param("nodesJSON", nodesJSON).
Exist()
if err != nil {
return err
}
if isDone {
err = this.Query(tx).
Pk(keyId).
Set("isDone", isDone).
UpdateQuickly()
if err != nil {
return err
}
// 检查任务是否已经完成
taskIsNotDone, err := this.Query(tx).
Attr("taskId", taskId).
Attr("isDone", false).
Exist()
if err != nil {
return err
}
var taskIsDone = !taskIsNotDone
var hasErrors = true
if taskIsDone {
// 已经完成,是否有错误
hasErrors, err = this.Query(tx).
Attr("taskId", taskId).
Where("JSON_LENGTH(errors)>0").
Exist()
if err != nil {
return err
}
}
err = SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, taskIsDone, !hasErrors)
if err != nil {
return err
}
}
return nil
}
// FindAllTaskKeys 查询某个任务下的所有Key
func (this *HTTPCacheTaskKeyDAO) FindAllTaskKeys(tx *dbs.Tx, taskId int64) (result []*HTTPCacheTaskKey, err error) {
_, err = this.Query(tx).
Attr("taskId", taskId).
AscPk().
Slice(&result).
FindAll()
return
}
// FindDoingTaskKeys 查询要执行的任务
func (this *HTTPCacheTaskKeyDAO) FindDoingTaskKeys(tx *dbs.Tx, nodeId int64, size int64) (result []*HTTPCacheTaskKey, err error) {
// 集群ID
clusterIds, err := SharedNodeDAO.FindEnabledAndOnNodeClusterIds(tx, nodeId)
if err != nil {
return nil, err
}
if len(clusterIds) == 0 {
return nil, nil
}
_, err = this.Query(tx).
Attr("clusterId", clusterIds).
Attr("isDone", false).
Where("NOT JSON_CONTAINS_PATH(nodes, 'one', :jsonPath1)").
Param("jsonPath1", "$.\""+types.String(nodeId)+"\"").
Where("taskId IN (SELECT id FROM " + SharedHTTPCacheTaskDAO.Table + " WHERE state=1 AND isReady=1 AND isDone=0)").
Limit(size).
AscPk().
Reuse(false).
Slice(&result).
FindAll()
if err != nil {
return nil, err
}
return
}
// ResetCacheKeysWithTaskId 重置任务下的Key状态
func (this *HTTPCacheTaskKeyDAO) ResetCacheKeysWithTaskId(tx *dbs.Tx, taskId int64) error {
return this.Query(tx).
Attr("taskId", taskId).
Set("isDone", false).
Set("nodes", "{}").
Set("errors", "{}").
UpdateQuickly()
}
// CountUserTasksInDay 读取某个用户当前数量
// day YYYYMMDD
func (this *HTTPCacheTaskKeyDAO) CountUserTasksInDay(tx *dbs.Tx, userId int64, day string, taskType HTTPCacheTaskType) (int64, error) {
if userId <= 0 {
return 0, nil
}
// 这里需要包含已删除的
return this.Query(tx).
Where("taskId IN (SELECT id FROM "+SharedHTTPCacheTaskDAO.Table+" WHERE userId=:userId AND day=:day AND type=:type)").
Param("userId", userId).
Param("day", day).
Param("type", taskType).
Count()
}
// Clean 清理以往的任务
func (this *HTTPCacheTaskKeyDAO) Clean(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Where("taskId IN (SELECT id FROM "+SharedHTTPCacheTaskDAO.Table+" WHERE day<=:day)").
Param("day", day).
Delete()
return err
}

View File

@@ -0,0 +1,54 @@
package models_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing"
)
func TestHTTPCacheTaskKeyDAO_CreateKey(t *testing.T) {
var dao = models.NewHTTPCacheTaskKeyDAO()
var tx *dbs.Tx
_, err := dao.CreateKey(tx, 1, "a", "purge", "key", 1)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestHTTPCacheTaskKeyDAO_UpdateKeyStatus(t *testing.T) {
dbs.NotifyReady()
var dao = models.NewHTTPCacheTaskKeyDAO()
var tx *dbs.Tx
var errString = "" // "this is error"
err := dao.UpdateKeyStatus(tx, 3, 1, errString, []byte(`{"1":true}`))
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestHTTPCacheTaskKeyDAO_CountUserTasksInDay(t *testing.T) {
dbs.NotifyReady()
var dao = models.NewHTTPCacheTaskKeyDAO()
var tx *dbs.Tx
{
count, err := dao.CountUserTasksInDay(tx, 1, timeutil.Format("Ymd"), models.HTTPCacheTaskTypePurge)
if err != nil {
t.Fatal(err)
}
t.Log("count:", count)
}
{
count, err := dao.CountUserTasksInDay(tx, 1, timeutil.Format("Ymd"), models.HTTPCacheTaskTypeFetch)
if err != nil {
t.Fatal(err)
}
t.Log("count:", count)
}
}

View File

@@ -0,0 +1,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
// HTTPCacheTaskKey 缓存任务Key
type HTTPCacheTaskKey struct {
Id uint64 `field:"id"` // ID
TaskId uint64 `field:"taskId"` // 任务ID
Key string `field:"key"` // Key
KeyType string `field:"keyType"` // Key类型key|prefix
Type string `field:"type"` // 操作类型
ClusterId uint32 `field:"clusterId"` // 集群ID
Nodes dbs.JSON `field:"nodes"` // 节点
Errors dbs.JSON `field:"errors"` // 错误信息
IsDone bool `field:"isDone"` // 是否已完成
}
type HTTPCacheTaskKeyOperator struct {
Id interface{} // ID
TaskId interface{} // 任务ID
Key interface{} // Key
KeyType interface{} // Key类型key|prefix
Type interface{} // 操作类型
ClusterId interface{} // 集群ID
Nodes interface{} // 节点
Errors interface{} // 错误信息
IsDone interface{} // 是否已完成
}
func NewHTTPCacheTaskKeyOperator() *HTTPCacheTaskKeyOperator {
return &HTTPCacheTaskKeyOperator{}
}

View File

@@ -0,0 +1,20 @@
package models
import "encoding/json"
// DecodeNodes 解析已完成节点信息
func (this *HTTPCacheTaskKey) DecodeNodes() map[string]bool {
var result = map[string]bool{}
var nodesJSON = this.Nodes
if IsNull(nodesJSON) {
return result
}
err := json.Unmarshal(nodesJSON, &result)
if err != nil {
// ignore error
return result
}
return result
}

View File

@@ -0,0 +1,36 @@
package models
// HTTPCacheTask 缓存相关任务
type HTTPCacheTask struct {
Id uint64 `field:"id"` // ID
UserId uint32 `field:"userId"` // 用户ID
Type string `field:"type"` // 任务类型purge|fetch
KeyType string `field:"keyType"` // Key类型
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
DoneAt uint64 `field:"doneAt"` // 完成时间
Day string `field:"day"` // 创建日期YYYYMMDD
IsDone bool `field:"isDone"` // 是否已完成
IsOk bool `field:"isOk"` // 是否完全成功
IsReady uint8 `field:"isReady"` // 是否已准备好
Description string `field:"description"` // 描述
}
type HTTPCacheTaskOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
Type interface{} // 任务类型purge|fetch
KeyType interface{} // Key类型
State interface{} // 状态
CreatedAt interface{} // 创建时间
DoneAt interface{} // 完成时间
Day interface{} // 创建日期YYYYMMDD
IsDone interface{} // 是否已完成
IsOk interface{} // 是否完全成功
IsReady interface{} // 是否已准备好
Description interface{} // 描述
}
func NewHTTPCacheTaskOperator() *HTTPCacheTaskOperator {
return &HTTPCacheTaskOperator{}
}

View File

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

View File

@@ -80,10 +80,10 @@ func (this *HTTPDeflatePolicyDAO) ComposeDeflateConfig(tx *dbs.Tx, policyId int6
config := &serverconfigs.HTTPDeflateCompressionConfig{} config := &serverconfigs.HTTPDeflateCompressionConfig{}
config.Id = int64(policy.Id) config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1 config.IsOn = policy.IsOn
if IsNotNull(policy.MinLength) { if IsNotNull(policy.MinLength) {
minLengthConfig := &shared.SizeCapacity{} minLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.MinLength), minLengthConfig) err = json.Unmarshal(policy.MinLength, minLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -91,7 +91,7 @@ func (this *HTTPDeflatePolicyDAO) ComposeDeflateConfig(tx *dbs.Tx, policyId int6
} }
if IsNotNull(policy.MaxLength) { if IsNotNull(policy.MaxLength) {
maxLengthConfig := &shared.SizeCapacity{} maxLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(policy.MaxLength), maxLengthConfig) err = json.Unmarshal(policy.MaxLength, maxLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -101,7 +101,7 @@ func (this *HTTPDeflatePolicyDAO) ComposeDeflateConfig(tx *dbs.Tx, policyId int6
if IsNotNull(policy.Conds) { if IsNotNull(policy.Conds) {
condsConfig := &shared.HTTPRequestCondsConfig{} condsConfig := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(policy.Conds), condsConfig) err = json.Unmarshal(policy.Conds, condsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,17 +1,19 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPDeflatePolicy Gzip配置 // HTTPDeflatePolicy Gzip配置
type HTTPDeflatePolicy struct { type HTTPDeflatePolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Level uint32 `field:"level"` // 压缩级别 Level uint32 `field:"level"` // 压缩级别
MinLength string `field:"minLength"` // 可压缩最小值 MinLength dbs.JSON `field:"minLength"` // 可压缩最小值
MaxLength string `field:"maxLength"` // 可压缩最大值 MaxLength dbs.JSON `field:"maxLength"` // 可压缩最大值
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Conds string `field:"conds"` // 条件 Conds dbs.JSON `field:"conds"` // 条件
} }
type HTTPDeflatePolicyOperator struct { type HTTPDeflatePolicyOperator struct {

View File

@@ -81,12 +81,12 @@ func (this *HTTPFastcgiDAO) ComposeFastcgiConfig(tx *dbs.Tx, fastcgiId int64) (*
} }
config := &serverconfigs.HTTPFastcgiConfig{} config := &serverconfigs.HTTPFastcgiConfig{}
config.Id = int64(fastcgi.Id) config.Id = int64(fastcgi.Id)
config.IsOn = fastcgi.IsOn == 1 config.IsOn = fastcgi.IsOn
config.Address = fastcgi.Address config.Address = fastcgi.Address
if IsNotNull(fastcgi.Params) { if IsNotNull(fastcgi.Params) {
params := []*serverconfigs.HTTPFastcgiParam{} params := []*serverconfigs.HTTPFastcgiParam{}
err = json.Unmarshal([]byte(fastcgi.Params), &params) err = json.Unmarshal(fastcgi.Params, &params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -95,7 +95,7 @@ func (this *HTTPFastcgiDAO) ComposeFastcgiConfig(tx *dbs.Tx, fastcgiId int64) (*
if IsNotNull(fastcgi.ReadTimeout) { if IsNotNull(fastcgi.ReadTimeout) {
duration := &shared.TimeDuration{} duration := &shared.TimeDuration{}
err = json.Unmarshal([]byte(fastcgi.ReadTimeout), duration) err = json.Unmarshal(fastcgi.ReadTimeout, duration)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -104,7 +104,7 @@ func (this *HTTPFastcgiDAO) ComposeFastcgiConfig(tx *dbs.Tx, fastcgiId int64) (*
if IsNotNull(fastcgi.ConnTimeout) { if IsNotNull(fastcgi.ConnTimeout) {
duration := &shared.TimeDuration{} duration := &shared.TimeDuration{}
err = json.Unmarshal([]byte(fastcgi.ConnTimeout), duration) err = json.Unmarshal(fastcgi.ConnTimeout, duration)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,18 +1,20 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPFastcgi Fastcgi设置 // HTTPFastcgi Fastcgi设置
type HTTPFastcgi struct { type HTTPFastcgi struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Address string `field:"address"` // 地址 Address string `field:"address"` // 地址
Params string `field:"params"` // 参数 Params dbs.JSON `field:"params"` // 参数
ReadTimeout string `field:"readTimeout"` // 读取超时 ReadTimeout dbs.JSON `field:"readTimeout"` // 读取超时
ConnTimeout string `field:"connTimeout"` // 连接超时 ConnTimeout dbs.JSON `field:"connTimeout"` // 连接超时
PoolSize uint32 `field:"poolSize"` // 连接池尺寸 PoolSize uint32 `field:"poolSize"` // 连接池尺寸
PathInfoPattern string `field:"pathInfoPattern"` // PATH_INFO匹配 PathInfoPattern string `field:"pathInfoPattern"` // PATH_INFO匹配
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
type HTTPFastcgiOperator struct { type HTTPFastcgiOperator struct {

View File

@@ -2,6 +2,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
@@ -116,7 +117,7 @@ func (this *HTTPFirewallPolicyDAO) FindAllEnabledFirewallPolicies(tx *dbs.Tx) (r
// CreateFirewallPolicy 创建策略 // CreateFirewallPolicy 创建策略
func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64, serverGroupId int64, serverId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte) (int64, error) { func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64, serverGroupId int64, serverId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte) (int64, error) {
op := NewHTTPFirewallPolicyOperator() var op = NewHTTPFirewallPolicyOperator()
op.UserId = userId op.UserId = userId
op.GroupId = serverGroupId op.GroupId = serverGroupId
op.ServerId = serverId op.ServerId = serverId
@@ -130,14 +131,31 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
if len(outboundJSON) > 0 { if len(outboundJSON) > 0 {
op.Outbound = outboundJSON op.Outbound = outboundJSON
} }
op.UseLocalFirewall = true
{ if userId <= 0 && serverGroupId <=0 && serverId <= 0 {
synFloodJSON, err := json.Marshal(firewallconfigs.DefaultSYNFloodConfig()) // synFlood
var synFloodConfig = firewallconfigs.DefaultSYNFloodConfig()
synFloodJSON, err := json.Marshal(synFloodConfig)
if err != nil { if err != nil {
return 0, err return 0, err
} }
op.SynFlood = synFloodJSON op.SynFlood = synFloodJSON
// block options
var blockOptions = firewallconfigs.DefaultHTTPFirewallBlockAction()
blockOptionsJSON, err := json.Marshal(blockOptions)
if err != nil {
return 0, err
}
op.BlockOptions = blockOptionsJSON
// captcha options
var captchaOptions = firewallconfigs.DefaultHTTPFirewallCaptchaAction()
captchaOptionsJSON, err := json.Marshal(captchaOptions)
if err != nil {
return 0, err
}
op.CaptchaOptions = captchaOptionsJSON
} }
err := this.Save(tx, op) err := this.Save(tx, op)
@@ -159,8 +177,8 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
groupCodes = append(groupCodes, group.Code) groupCodes = append(groupCodes, group.Code)
} }
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true} var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
outboundConfig := &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true} var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
if templatePolicy.Inbound != nil { if templatePolicy.Inbound != nil {
for _, group := range templatePolicy.Inbound.Groups { for _, group := range templatePolicy.Inbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code) isOn := lists.ContainsString(groupCodes, group.Code)
@@ -206,6 +224,7 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
if err != nil { if err != nil {
return 0, err return 0, err
} }
return policyId, nil return policyId, nil
} }
@@ -259,11 +278,23 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
} }
// UpdateFirewallPolicy 修改策略 // UpdateFirewallPolicy 修改策略
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte, blockOptionsJSON []byte, mode firewallconfigs.FirewallMode, useLocalFirewall bool, synFloodConfig *firewallconfigs.SYNFloodConfig) error { func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
policyId int64,
isOn bool,
name string,
description string,
inboundJSON []byte,
outboundJSON []byte,
blockOptionsJSON []byte,
captchaOptionsJSON []byte,
mode firewallconfigs.FirewallMode,
useLocalFirewall bool,
synFloodConfig *firewallconfigs.SYNFloodConfig,
logConfig *firewallconfigs.HTTPFirewallPolicyLogConfig) error {
if policyId <= 0 { if policyId <= 0 {
return errors.New("invalid policyId") return errors.New("invalid policyId")
} }
op := NewHTTPFirewallPolicyOperator() var op = NewHTTPFirewallPolicyOperator()
op.Id = policyId op.Id = policyId
op.IsOn = isOn op.IsOn = isOn
op.Name = name op.Name = name
@@ -279,9 +310,12 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int
} else { } else {
op.Outbound = "null" op.Outbound = "null"
} }
if len(blockOptionsJSON) > 0 { if IsNotNull(blockOptionsJSON) {
op.BlockOptions = blockOptionsJSON op.BlockOptions = blockOptionsJSON
} }
if IsNotNull(captchaOptionsJSON) {
op.CaptchaOptions = captchaOptionsJSON
}
if synFloodConfig != nil { if synFloodConfig != nil {
synFloodConfigJSON, err := json.Marshal(synFloodConfig) synFloodConfigJSON, err := json.Marshal(synFloodConfig)
@@ -293,6 +327,16 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int
op.SynFlood = "null" op.SynFlood = "null"
} }
if logConfig != nil {
logJSON, err := json.Marshal(logConfig)
if err != nil {
return err
}
op.Log = logJSON
} else {
op.Log = "null"
}
op.UseLocalFirewall = useLocalFirewall op.UseLocalFirewall = useLocalFirewall
err := this.Save(tx, op) err := this.Save(tx, op)
if err != nil { if err != nil {
@@ -311,7 +355,7 @@ func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx, c
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
return query. return query.
State(HTTPFirewallPolicyStateEnabled). State(HTTPFirewallPolicyStateEnabled).
@@ -330,7 +374,7 @@ func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, clust
} }
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword)"). query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%") Param("keyword", dbutils.QuoteLike(keyword))
} }
_, err = query. _, err = query.
State(HTTPFirewallPolicyStateEnabled). State(HTTPFirewallPolicyStateEnabled).
@@ -364,9 +408,9 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
return nil, nil return nil, nil
} }
config := &firewallconfigs.HTTPFirewallPolicy{} var config = &firewallconfigs.HTTPFirewallPolicy{}
config.Id = int64(policy.Id) config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1 config.IsOn = policy.IsOn
config.Name = policy.Name config.Name = policy.Name
config.Description = policy.Description config.Description = policy.Description
config.UseLocalFirewall = policy.UseLocalFirewall == 1 config.UseLocalFirewall = policy.UseLocalFirewall == 1
@@ -379,7 +423,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
// Inbound // Inbound
inbound := &firewallconfigs.HTTPFirewallInboundConfig{} inbound := &firewallconfigs.HTTPFirewallInboundConfig{}
if IsNotNull(policy.Inbound) { if IsNotNull(policy.Inbound) {
err = json.Unmarshal([]byte(policy.Inbound), inbound) err = json.Unmarshal(policy.Inbound, inbound)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -407,7 +451,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
// Outbound // Outbound
outbound := &firewallconfigs.HTTPFirewallOutboundConfig{} outbound := &firewallconfigs.HTTPFirewallOutboundConfig{}
if IsNotNull(policy.Outbound) { if IsNotNull(policy.Outbound) {
err = json.Unmarshal([]byte(policy.Outbound), outbound) err = json.Unmarshal(policy.Outbound, outbound)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -434,24 +478,46 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
// Block动作配置 // Block动作配置
if IsNotNull(policy.BlockOptions) { if IsNotNull(policy.BlockOptions) {
blockAction := &firewallconfigs.HTTPFirewallBlockAction{} var blockAction = &firewallconfigs.HTTPFirewallBlockAction{}
err = json.Unmarshal([]byte(policy.BlockOptions), blockAction) err = json.Unmarshal(policy.BlockOptions, blockAction)
if err != nil { if err != nil {
return config, err return config, err
} }
config.BlockOptions = blockAction config.BlockOptions = blockAction
} }
// Captcha动作配置
if IsNotNull(policy.CaptchaOptions) {
var captchaAction = &firewallconfigs.HTTPFirewallCaptchaAction{}
err = json.Unmarshal(policy.CaptchaOptions, captchaAction)
if err != nil {
return config, err
}
config.CaptchaOptions = captchaAction
}
// syn flood // syn flood
if len(policy.SynFlood) > 0 { if IsNotNull(policy.SynFlood) {
var synFloodConfig = &firewallconfigs.SYNFloodConfig{} var synFloodConfig = &firewallconfigs.SYNFloodConfig{}
err = json.Unmarshal([]byte(policy.SynFlood), synFloodConfig) err = json.Unmarshal(policy.SynFlood, synFloodConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.SYNFlood = synFloodConfig config.SYNFlood = synFloodConfig
} }
// log
if IsNotNull(policy.Log) {
var logConfig = &firewallconfigs.HTTPFirewallPolicyLogConfig{}
err = json.Unmarshal(policy.Log, logConfig)
if err != nil {
return nil, err
}
config.Log = logConfig
} else {
config.Log = firewallconfigs.DefaultHTTPFirewallPolicyLogConfig
}
if cacheMap != nil { if cacheMap != nil {
cacheMap.Put(cacheKey, config) cacheMap.Put(cacheKey, config)
} }
@@ -492,6 +558,7 @@ func (this *HTTPFirewallPolicyDAO) CheckUserFirewallPolicy(tx *dbs.Tx, userId in
} }
// FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略 // FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略
// TODO 改成通过 serverId 查询
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *dbs.Tx, ipListId int64) ([]int64, error) { func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *dbs.Tx, ipListId int64) ([]int64, error) {
ones, err := this.Query(tx). ones, err := this.Query(tx).
ResultPk(). ResultPk().
@@ -510,6 +577,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *
} }
// FindEnabledFirewallPolicyWithIPListId 查找使用某个IPList的策略 // FindEnabledFirewallPolicyWithIPListId 查找使用某个IPList的策略
// TODO 改成通过 serverId 查询
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyWithIPListId(tx *dbs.Tx, ipListId int64) (*HTTPFirewallPolicy, error) { func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyWithIPListId(tx *dbs.Tx, ipListId int64) (*HTTPFirewallPolicy, error) {
one, err := this.Query(tx). one, err := this.Query(tx).
State(HTTPFirewallPolicyStateEnabled). State(HTTPFirewallPolicyStateEnabled).

View File

@@ -1,24 +1,28 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPFirewallPolicy HTTP防火墙 // HTTPFirewallPolicy HTTP防火墙
type HTTPFirewallPolicy struct { type HTTPFirewallPolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
ServerId uint32 `field:"serverId"` // 服务ID ServerId uint32 `field:"serverId"` // 服务ID
GroupId uint32 `field:"groupId"` // 服务分组ID GroupId uint32 `field:"groupId"` // 服务分组ID
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Inbound string `field:"inbound"` // 入站规则 Inbound dbs.JSON `field:"inbound"` // 入站规则
Outbound string `field:"outbound"` // 出站规则 Outbound dbs.JSON `field:"outbound"` // 出站规则
BlockOptions string `field:"blockOptions"` // BLOCK选项 BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
Mode string `field:"mode"` // 模式 CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙 Mode string `field:"mode"` // 模式
SynFlood string `field:"synFlood"` // SynFlood防御设置 UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
Log dbs.JSON `field:"log"` // 日志配置
} }
type HTTPFirewallPolicyOperator struct { type HTTPFirewallPolicyOperator struct {
@@ -36,9 +40,11 @@ type HTTPFirewallPolicyOperator struct {
Inbound interface{} // 入站规则 Inbound interface{} // 入站规则
Outbound interface{} // 出站规则 Outbound interface{} // 出站规则
BlockOptions interface{} // BLOCK选项 BlockOptions interface{} // BLOCK选项
CaptchaOptions interface{} // 验证码选项
Mode interface{} // 模式 Mode interface{} // 模式
UseLocalFirewall interface{} // 是否自动使用本地防火墙 UseLocalFirewall interface{} // 是否自动使用本地防火墙
SynFlood interface{} // SynFlood防御设置 SynFlood interface{} // SynFlood防御设置
Log interface{} // 日志配置
} }
func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator { func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator {

View File

@@ -35,12 +35,12 @@ func init() {
}) })
} }
// 初始化 // Init 初始化
func (this *HTTPFirewallRuleDAO) Init() { func (this *HTTPFirewallRuleDAO) Init() {
_ = this.DAOObject.Init() _ = this.DAOObject.Init()
} }
// 启用条目 // EnableHTTPFirewallRule 启用条目
func (this *HTTPFirewallRuleDAO) EnableHTTPFirewallRule(tx *dbs.Tx, id int64) error { func (this *HTTPFirewallRuleDAO) EnableHTTPFirewallRule(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -49,7 +49,7 @@ func (this *HTTPFirewallRuleDAO) EnableHTTPFirewallRule(tx *dbs.Tx, id int64) er
return err return err
} }
// 禁用条目 // DisableHTTPFirewallRule 禁用条目
func (this *HTTPFirewallRuleDAO) DisableHTTPFirewallRule(tx *dbs.Tx, ruleId int64) error { func (this *HTTPFirewallRuleDAO) DisableHTTPFirewallRule(tx *dbs.Tx, ruleId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(ruleId). Pk(ruleId).
@@ -61,7 +61,7 @@ func (this *HTTPFirewallRuleDAO) DisableHTTPFirewallRule(tx *dbs.Tx, ruleId int6
return this.NotifyUpdate(tx, ruleId) return this.NotifyUpdate(tx, ruleId)
} }
// 查找启用中的条目 // FindEnabledHTTPFirewallRule 查找启用中的条目
func (this *HTTPFirewallRuleDAO) FindEnabledHTTPFirewallRule(tx *dbs.Tx, id int64) (*HTTPFirewallRule, error) { func (this *HTTPFirewallRuleDAO) FindEnabledHTTPFirewallRule(tx *dbs.Tx, id int64) (*HTTPFirewallRule, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Pk(id).
@@ -73,7 +73,7 @@ func (this *HTTPFirewallRuleDAO) FindEnabledHTTPFirewallRule(tx *dbs.Tx, id int6
return result.(*HTTPFirewallRule), err return result.(*HTTPFirewallRule), err
} }
// 组合配置 // ComposeFirewallRule 组合配置
func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (*firewallconfigs.HTTPFirewallRule, error) { func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (*firewallconfigs.HTTPFirewallRule, error) {
rule, err := this.FindEnabledHTTPFirewallRule(tx, ruleId) rule, err := this.FindEnabledHTTPFirewallRule(tx, ruleId)
if err != nil { if err != nil {
@@ -84,12 +84,12 @@ func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (
} }
config := &firewallconfigs.HTTPFirewallRule{} config := &firewallconfigs.HTTPFirewallRule{}
config.Id = int64(rule.Id) config.Id = int64(rule.Id)
config.IsOn = rule.IsOn == 1 config.IsOn = rule.IsOn
config.Param = rule.Param config.Param = rule.Param
paramFilters := []*firewallconfigs.ParamFilter{} paramFilters := []*firewallconfigs.ParamFilter{}
if IsNotNull(rule.ParamFilters) { if IsNotNull(rule.ParamFilters) {
err = json.Unmarshal([]byte(rule.ParamFilters), &paramFilters) err = json.Unmarshal(rule.ParamFilters, &paramFilters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -98,11 +98,11 @@ func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (
config.Operator = rule.Operator config.Operator = rule.Operator
config.Value = rule.Value config.Value = rule.Value
config.IsCaseInsensitive = rule.IsCaseInsensitive == 1 config.IsCaseInsensitive = rule.IsCaseInsensitive
if IsNotNull(rule.CheckpointOptions) { if IsNotNull(rule.CheckpointOptions) {
checkpointOptions := map[string]interface{}{} checkpointOptions := map[string]interface{}{}
err = json.Unmarshal([]byte(rule.CheckpointOptions), &checkpointOptions) err = json.Unmarshal(rule.CheckpointOptions, &checkpointOptions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -114,7 +114,7 @@ func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (
return config, nil return config, nil
} }
// 从配置中配置规则 // CreateOrUpdateRuleFromConfig 从配置中配置规则
func (this *HTTPFirewallRuleDAO) CreateOrUpdateRuleFromConfig(tx *dbs.Tx, ruleConfig *firewallconfigs.HTTPFirewallRule) (int64, error) { func (this *HTTPFirewallRuleDAO) CreateOrUpdateRuleFromConfig(tx *dbs.Tx, ruleConfig *firewallconfigs.HTTPFirewallRule) (int64, error) {
op := NewHTTPFirewallRuleOperator() op := NewHTTPFirewallRuleOperator()
op.Id = ruleConfig.Id op.Id = ruleConfig.Id
@@ -160,7 +160,7 @@ func (this *HTTPFirewallRuleDAO) CreateOrUpdateRuleFromConfig(tx *dbs.Tx, ruleCo
return types.Int64(op.Id), nil return types.Int64(op.Id), nil
} }
// 通知更新 // NotifyUpdate 通知更新
func (this *HTTPFirewallRuleDAO) NotifyUpdate(tx *dbs.Tx, ruleId int64) error { func (this *HTTPFirewallRuleDAO) NotifyUpdate(tx *dbs.Tx, ruleId int64) error {
setId, err := SharedHTTPFirewallRuleSetDAO.FindEnabledRuleSetIdWithRuleId(tx, ruleId) setId, err := SharedHTTPFirewallRuleSetDAO.FindEnabledRuleSetIdWithRuleId(tx, ruleId)
if err != nil { if err != nil {

View File

@@ -91,15 +91,15 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
} }
config := &firewallconfigs.HTTPFirewallRuleGroup{} config := &firewallconfigs.HTTPFirewallRuleGroup{}
config.Id = int64(group.Id) config.Id = int64(group.Id)
config.IsOn = group.IsOn == 1 config.IsOn = group.IsOn
config.Name = group.Name config.Name = group.Name
config.Description = group.Description config.Description = group.Description
config.Code = group.Code config.Code = group.Code
config.IsTemplate = group.IsTemplate == 1 config.IsTemplate = group.IsTemplate
if IsNotNull(group.Sets) { if IsNotNull(group.Sets) {
setRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{} setRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
err = json.Unmarshal([]byte(group.Sets), &setRefs) err = json.Unmarshal(group.Sets, &setRefs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,18 +1,20 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPFirewallRuleGroup 防火墙规则分组 // HTTPFirewallRuleGroup 防火墙规则分组
type HTTPFirewallRuleGroup struct { type HTTPFirewallRuleGroup struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Code string `field:"code"` // 代号 Code string `field:"code"` // 代号
IsTemplate uint8 `field:"isTemplate"` // 是否为预置模板 IsTemplate bool `field:"isTemplate"` // 是否为预置模板
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
Sets string `field:"sets"` // 规则集列表 Sets dbs.JSON `field:"sets"` // 规则集列表
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
} }
type HTTPFirewallRuleGroupOperator struct { type HTTPFirewallRuleGroupOperator struct {

View File

@@ -1,20 +1,22 @@
package models package models
// 防火墙规则 import "github.com/iwind/TeaGo/dbs"
// HTTPFirewallRule 防火墙规则
type HTTPFirewallRule struct { type HTTPFirewallRule struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Description string `field:"description"` // 说明 Description string `field:"description"` // 说明
Param string `field:"param"` // 参数 Param string `field:"param"` // 参数
ParamFilters string `field:"paramFilters"` // 处理器 ParamFilters dbs.JSON `field:"paramFilters"` // 处理器
Operator string `field:"operator"` // 操作符 Operator string `field:"operator"` // 操作符
Value string `field:"value"` // 对比值 Value string `field:"value"` // 对比值
IsCaseInsensitive uint8 `field:"isCaseInsensitive"` // 是否大小写不敏感 IsCaseInsensitive bool `field:"isCaseInsensitive"` // 是否大小写不敏感
CheckpointOptions string `field:"checkpointOptions"` // 检查点参数 CheckpointOptions dbs.JSON `field:"checkpointOptions"` // 检查点参数
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
} }
type HTTPFirewallRuleOperator struct { type HTTPFirewallRuleOperator struct {

View File

@@ -94,7 +94,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
} }
config := &firewallconfigs.HTTPFirewallRuleSet{} config := &firewallconfigs.HTTPFirewallRuleSet{}
config.Id = int64(set.Id) config.Id = int64(set.Id)
config.IsOn = set.IsOn == 1 config.IsOn = set.IsOn
config.Name = set.Name config.Name = set.Name
config.Description = set.Description config.Description = set.Description
config.Code = set.Code config.Code = set.Code
@@ -103,7 +103,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
if IsNotNull(set.Rules) { if IsNotNull(set.Rules) {
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{} ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal([]byte(set.Rules), &ruleRefs) err = json.Unmarshal(set.Rules, &ruleRefs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -121,7 +121,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{} var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
if len(set.Actions) > 0 { if len(set.Actions) > 0 {
err = json.Unmarshal([]byte(set.Actions), &actionConfigs) err = json.Unmarshal(set.Actions, &actionConfigs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,22 +1,24 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPFirewallRuleSet 防火墙规则集 // HTTPFirewallRuleSet 防火墙规则集
type HTTPFirewallRuleSet struct { type HTTPFirewallRuleSet struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Code string `field:"code"` // 代号 Code string `field:"code"` // 代号
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Rules string `field:"rules"` // 规则列表 Rules dbs.JSON `field:"rules"` // 规则列表
Connector string `field:"connector"` // 规则之间的关系 Connector string `field:"connector"` // 规则之间的关系
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
Action string `field:"action"` // 执行的动作(过期) Action string `field:"action"` // 执行的动作(过期)
ActionOptions string `field:"actionOptions"` // 动作的选项(过期) ActionOptions dbs.JSON `field:"actionOptions"` // 动作的选项(过期)
Actions string `field:"actions"` // 一组动作 Actions dbs.JSON `field:"actions"` // 一组动作
IgnoreLocal uint8 `field:"ignoreLocal"` // 忽略局域网请求 IgnoreLocal uint8 `field:"ignoreLocal"` // 忽略局域网请求
} }
type HTTPFirewallRuleSetOperator struct { type HTTPFirewallRuleSetOperator struct {

View File

@@ -88,10 +88,10 @@ func (this *HTTPGzipDAO) ComposeGzipConfig(tx *dbs.Tx, gzipId int64) (*servercon
config := &serverconfigs.HTTPGzipCompressionConfig{} config := &serverconfigs.HTTPGzipCompressionConfig{}
config.Id = int64(gzip.Id) config.Id = int64(gzip.Id)
config.IsOn = gzip.IsOn == 1 config.IsOn = gzip.IsOn
if IsNotNull(gzip.MinLength) { if IsNotNull(gzip.MinLength) {
minLengthConfig := &shared.SizeCapacity{} minLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(gzip.MinLength), minLengthConfig) err = json.Unmarshal(gzip.MinLength, minLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -99,7 +99,7 @@ func (this *HTTPGzipDAO) ComposeGzipConfig(tx *dbs.Tx, gzipId int64) (*servercon
} }
if IsNotNull(gzip.MaxLength) { if IsNotNull(gzip.MaxLength) {
maxLengthConfig := &shared.SizeCapacity{} maxLengthConfig := &shared.SizeCapacity{}
err = json.Unmarshal([]byte(gzip.MaxLength), maxLengthConfig) err = json.Unmarshal(gzip.MaxLength, maxLengthConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -109,7 +109,7 @@ func (this *HTTPGzipDAO) ComposeGzipConfig(tx *dbs.Tx, gzipId int64) (*servercon
if IsNotNull(gzip.Conds) { if IsNotNull(gzip.Conds) {
condsConfig := &shared.HTTPRequestCondsConfig{} condsConfig := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(gzip.Conds), condsConfig) err = json.Unmarshal(gzip.Conds, condsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,17 +1,19 @@
package models package models
// Gzip配置 import "github.com/iwind/TeaGo/dbs"
// HTTPGzip Gzip配置
type HTTPGzip struct { type HTTPGzip struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Level uint32 `field:"level"` // 压缩级别 Level uint32 `field:"level"` // 压缩级别
MinLength string `field:"minLength"` // 可压缩最小值 MinLength dbs.JSON `field:"minLength"` // 可压缩最小值
MaxLength string `field:"maxLength"` // 可压缩最大值 MaxLength dbs.JSON `field:"maxLength"` // 可压缩最大值
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Conds string `field:"conds"` // 条件 Conds dbs.JSON `field:"conds"` // 条件
} }
type HTTPGzipOperator struct { type HTTPGzipOperator struct {

View File

@@ -5,22 +5,22 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
) )
// 解析最小长度 // DecodeMinLength 解析最小长度
func (this *HTTPGzip) DecodeMinLength() (*shared.SizeCapacity, error) { func (this *HTTPGzip) DecodeMinLength() (*shared.SizeCapacity, error) {
if len(this.MinLength) == 0 { if len(this.MinLength) == 0 {
return nil, nil return nil, nil
} }
capacity := &shared.SizeCapacity{} capacity := &shared.SizeCapacity{}
err := json.Unmarshal([]byte(this.MinLength), capacity) err := json.Unmarshal(this.MinLength, capacity)
return capacity, err return capacity, err
} }
// 解析最大长度 // DecodeMaxLength 解析最大长度
func (this *HTTPGzip) DecodeMaxLength() (*shared.SizeCapacity, error) { func (this *HTTPGzip) DecodeMaxLength() (*shared.SizeCapacity, error) {
if len(this.MaxLength) == 0 { if len(this.MaxLength) == 0 {
return nil, nil return nil, nil
} }
capacity := &shared.SizeCapacity{} capacity := &shared.SizeCapacity{}
err := json.Unmarshal([]byte(this.MaxLength), capacity) err := json.Unmarshal(this.MaxLength, capacity)
return capacity, err return capacity, err
} }

View File

@@ -236,7 +236,7 @@ func (this *HTTPHeaderDAO) ComposeHeaderConfig(tx *dbs.Tx, headerId int64) (*sha
config := &shared.HTTPHeaderConfig{} config := &shared.HTTPHeaderConfig{}
config.Id = int64(header.Id) config.Id = int64(header.Id)
config.IsOn = header.IsOn == 1 config.IsOn = header.IsOn
config.Name = header.Name config.Name = header.Name
config.Value = header.Value config.Value = header.Value
config.DisableRedirect = header.DisableRedirect == 1 config.DisableRedirect = header.DisableRedirect == 1
@@ -244,9 +244,9 @@ func (this *HTTPHeaderDAO) ComposeHeaderConfig(tx *dbs.Tx, headerId int64) (*sha
// replace // replace
config.ShouldReplace = header.ShouldReplace == 1 config.ShouldReplace = header.ShouldReplace == 1
if len(header.ReplaceValues) > 0 { if IsNotNull(header.ReplaceValues) {
var values = []*shared.HTTPHeaderReplaceValue{} var values = []*shared.HTTPHeaderReplaceValue{}
err = json.Unmarshal([]byte(header.ReplaceValues), &values) err = json.Unmarshal(header.ReplaceValues, &values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -254,9 +254,9 @@ func (this *HTTPHeaderDAO) ComposeHeaderConfig(tx *dbs.Tx, headerId int64) (*sha
} }
// status // status
if len(header.Status) > 0 { if IsNotNull(header.Status) {
status := &shared.HTTPStatusConfig{} status := &shared.HTTPStatusConfig{}
err = json.Unmarshal([]byte(header.Status), status) err = json.Unmarshal(header.Status, status)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -264,9 +264,9 @@ func (this *HTTPHeaderDAO) ComposeHeaderConfig(tx *dbs.Tx, headerId int64) (*sha
} }
// methods // methods
if len(header.Methods) > 0 { if IsNotNull(header.Methods) {
var methods = []string{} var methods = []string{}
err = json.Unmarshal([]byte(header.Methods), &methods) err = json.Unmarshal(header.Methods, &methods)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -274,9 +274,9 @@ func (this *HTTPHeaderDAO) ComposeHeaderConfig(tx *dbs.Tx, headerId int64) (*sha
} }
// domains // domains
if len(header.Domains) > 0 { if IsNotNull(header.Domains) {
var domains = []string{} var domains = []string{}
err = json.Unmarshal([]byte(header.Domains), &domains) err = json.Unmarshal(header.Domains, &domains)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,24 +1,26 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPHeader HTTP Header // HTTPHeader HTTP Header
type HTTPHeader struct { type HTTPHeader struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Value string `field:"value"` // 值 Value string `field:"value"` // 值
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
Status string `field:"status"` // 状态码设置 Status dbs.JSON `field:"status"` // 状态码设置
DisableRedirect uint8 `field:"disableRedirect"` // 是否不支持跳转 DisableRedirect uint8 `field:"disableRedirect"` // 是否不支持跳转
ShouldAppend uint8 `field:"shouldAppend"` // 是否为附加 ShouldAppend uint8 `field:"shouldAppend"` // 是否为附加
ShouldReplace uint8 `field:"shouldReplace"` // 是否替换变量 ShouldReplace uint8 `field:"shouldReplace"` // 是否替换变量
ReplaceValues string `field:"replaceValues"` // 替换的值 ReplaceValues dbs.JSON `field:"replaceValues"` // 替换的值
Methods string `field:"methods"` // 支持的方法 Methods dbs.JSON `field:"methods"` // 支持的方法
Domains string `field:"domains"` // 支持的域名 Domains dbs.JSON `field:"domains"` // 支持的域名
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
} }
type HTTPHeaderOperator struct { type HTTPHeaderOperator struct {

View File

@@ -184,12 +184,12 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
config := &shared.HTTPHeaderPolicy{} config := &shared.HTTPHeaderPolicy{}
config.Id = int64(policy.Id) config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1 config.IsOn = policy.IsOn
// SetHeaders // SetHeaders
if len(policy.SetHeaders) > 0 { if IsNotNull(policy.SetHeaders) {
refs := []*shared.HTTPHeaderRef{} refs := []*shared.HTTPHeaderRef{}
err = json.Unmarshal([]byte(policy.SetHeaders), &refs) err = json.Unmarshal(policy.SetHeaders, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -211,9 +211,9 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
} }
// Delete Headers // Delete Headers
if len(policy.DeleteHeaders) > 0 { if IsNotNull(policy.DeleteHeaders) {
headers := []string{} headers := []string{}
err = json.Unmarshal([]byte(policy.DeleteHeaders), &headers) err = json.Unmarshal(policy.DeleteHeaders, &headers)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,19 +1,21 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// //
type HTTPHeaderPolicy struct { type HTTPHeaderPolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
AddHeaders string `field:"addHeaders"` // 添加的Header AddHeaders dbs.JSON `field:"addHeaders"` // 添加的Header
AddTrailers string `field:"addTrailers"` // 添加的Trailers AddTrailers dbs.JSON `field:"addTrailers"` // 添加的Trailers
SetHeaders string `field:"setHeaders"` // 设置Header SetHeaders dbs.JSON `field:"setHeaders"` // 设置Header
ReplaceHeaders string `field:"replaceHeaders"` // 替换Header内容 ReplaceHeaders dbs.JSON `field:"replaceHeaders"` // 替换Header内容
Expires string `field:"expires"` // Expires单独设置 Expires dbs.JSON `field:"expires"` // Expires单独设置
DeleteHeaders string `field:"deleteHeaders"` // 删除的Headers DeleteHeaders dbs.JSON `field:"deleteHeaders"` // 删除的Headers
} }
type HTTPHeaderPolicyOperator struct { type HTTPHeaderPolicyOperator struct {

View File

@@ -170,12 +170,12 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
config := &serverconfigs.HTTPLocationConfig{} config := &serverconfigs.HTTPLocationConfig{}
config.Id = int64(location.Id) config.Id = int64(location.Id)
config.IsOn = location.IsOn == 1 config.IsOn = location.IsOn
config.Description = location.Description config.Description = location.Description
config.Name = location.Name config.Name = location.Name
config.Pattern = location.Pattern config.Pattern = location.Pattern
config.URLPrefix = location.UrlPrefix config.URLPrefix = location.UrlPrefix
config.IsBreak = location.IsBreak == 1 config.IsBreak = location.IsBreak
// web // web
if location.WebId > 0 { if location.WebId > 0 {
@@ -189,7 +189,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
// reverse proxy // reverse proxy
if IsNotNull(location.ReverseProxy) { if IsNotNull(location.ReverseProxy) {
ref := &serverconfigs.ReverseProxyRef{} ref := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal([]byte(location.ReverseProxy), ref) err = json.Unmarshal(location.ReverseProxy, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -204,9 +204,9 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
} }
// conds // conds
if len(location.Conds) > 0 { if IsNotNull(location.Conds) {
conds := &shared.HTTPRequestCondsConfig{} conds := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(location.Conds), conds) err = json.Unmarshal(location.Conds, conds)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -214,9 +214,9 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
} }
// domains // domains
if len(location.Domains) > 0 { if IsNotNull(location.Domains) {
var domains = []string{} var domains = []string{}
err = json.Unmarshal([]byte(location.Domains), &domains) err = json.Unmarshal(location.Domains, &domains)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -241,7 +241,7 @@ func (this *HTTPLocationDAO) FindLocationReverseProxy(tx *dbs.Tx, locationId int
if err != nil { if err != nil {
return nil, err return nil, err
} }
if IsNotNull(refString) { if IsNotNull([]byte(refString)) {
ref := &serverconfigs.ReverseProxyRef{} ref := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal([]byte(refString), ref) err = json.Unmarshal([]byte(refString), ref)
if err != nil { if err != nil {

View File

@@ -1,24 +1,26 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPLocation 路由规则配置 // HTTPLocation 路由规则配置
type HTTPLocation struct { type HTTPLocation struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
ParentId uint32 `field:"parentId"` // 父级ID ParentId uint32 `field:"parentId"` // 父级ID
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Pattern string `field:"pattern"` // 匹配规则 Pattern string `field:"pattern"` // 匹配规则
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
WebId uint32 `field:"webId"` // Web配置ID WebId uint32 `field:"webId"` // Web配置ID
ReverseProxy string `field:"reverseProxy"` // 反向代理 ReverseProxy dbs.JSON `field:"reverseProxy"` // 反向代理
UrlPrefix string `field:"urlPrefix"` // URL前缀 UrlPrefix string `field:"urlPrefix"` // URL前缀
IsBreak uint8 `field:"isBreak"` // 是否终止匹配 IsBreak bool `field:"isBreak"` // 是否终止匹配
Conds string `field:"conds"` // 匹配条件 Conds dbs.JSON `field:"conds"` // 匹配条件
Domains string `field:"domains"` // 专属域名 Domains dbs.JSON `field:"domains"` // 专属域名
} }
type HTTPLocationOperator struct { type HTTPLocationOperator struct {

View File

@@ -77,8 +77,9 @@ func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, e
} }
// CreatePage 创建Page // CreatePage 创建Page
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) (pageId int64, err error) { func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) (pageId int64, err error) {
op := NewHTTPPageOperator() op := NewHTTPPageOperator()
op.UserId = userId
op.IsOn = true op.IsOn = true
op.State = HTTPPageStateEnabled op.State = HTTPPageStateEnabled
@@ -154,7 +155,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
config := &serverconfigs.HTTPPageConfig{} config := &serverconfigs.HTTPPageConfig{}
config.Id = int64(page.Id) config.Id = int64(page.Id)
config.IsOn = page.IsOn == 1 config.IsOn = page.IsOn
config.NewStatus = int(page.NewStatus) config.NewStatus = int(page.NewStatus)
config.URL = page.Url config.URL = page.Url
config.Body = page.Body config.Body = page.Body
@@ -166,7 +167,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
if len(page.StatusList) > 0 { if len(page.StatusList) > 0 {
statusList := []string{} statusList := []string{}
err = json.Unmarshal([]byte(page.StatusList), &statusList) err = json.Unmarshal(page.StatusList, &statusList)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -182,6 +183,26 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
return config, nil return config, nil
} }
// CheckUserPage 检查用户页面
func (this *HTTPPageDAO) CheckUserPage(tx *dbs.Tx, userId int64, pageId int64) error {
if userId <= 0 || pageId <= 0 {
return ErrNotFound
}
b, err := this.Query(tx).
Pk(pageId).
Attr("userId", userId).
State(HTTPPageStateEnabled).
Exist()
if err != nil {
return err
}
if !b {
return ErrNotFound
}
return nil
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *HTTPPageDAO) NotifyUpdate(tx *dbs.Tx, pageId int64) error { func (this *HTTPPageDAO) NotifyUpdate(tx *dbs.Tx, pageId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithPageId(tx, pageId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithPageId(tx, pageId)

View File

@@ -1,18 +1,20 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPPage 特殊页面 // HTTPPage 特殊页面
type HTTPPage struct { type HTTPPage struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
StatusList string `field:"statusList"` // 状态列表 StatusList dbs.JSON `field:"statusList"` // 状态列表
Url string `field:"url"` // 页面URL Url string `field:"url"` // 页面URL
NewStatus int32 `field:"newStatus"` // 新状态码 NewStatus int32 `field:"newStatus"` // 新状态码
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Body string `field:"body"` // 页面内容 Body string `field:"body"` // 页面内容
BodyType string `field:"bodyType"` // 内容类型 BodyType string `field:"bodyType"` // 内容类型
} }
type HTTPPageOperator struct { type HTTPPageOperator struct {

View File

@@ -97,19 +97,19 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
config := &serverconfigs.HTTPRewriteRule{} config := &serverconfigs.HTTPRewriteRule{}
config.Id = int64(rule.Id) config.Id = int64(rule.Id)
config.IsOn = rule.IsOn == 1 config.IsOn = rule.IsOn
config.Pattern = rule.Pattern config.Pattern = rule.Pattern
config.Replace = rule.Replace config.Replace = rule.Replace
config.Mode = rule.Mode config.Mode = rule.Mode
config.RedirectStatus = types.Int(rule.RedirectStatus) config.RedirectStatus = types.Int(rule.RedirectStatus)
config.ProxyHost = rule.ProxyHost config.ProxyHost = rule.ProxyHost
config.IsBreak = rule.IsBreak == 1 config.IsBreak = rule.IsBreak
config.WithQuery = rule.WithQuery == 1 config.WithQuery = rule.WithQuery == 1
// conds // conds
if len(rule.Conds) > 0 { if len(rule.Conds) > 0 {
conds := &shared.HTTPRequestCondsConfig{} conds := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(rule.Conds), conds) err = json.Unmarshal(rule.Conds, conds)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,22 +1,24 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// 重写规则 // 重写规则
type HTTPRewriteRule struct { type HTTPRewriteRule struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Pattern string `field:"pattern"` // 匹配规则 Pattern string `field:"pattern"` // 匹配规则
Replace string `field:"replace"` // 跳转后的地址 Replace string `field:"replace"` // 跳转后的地址
Mode string `field:"mode"` // 替换模式 Mode string `field:"mode"` // 替换模式
RedirectStatus uint32 `field:"redirectStatus"` // 跳转的状态码 RedirectStatus uint32 `field:"redirectStatus"` // 跳转的状态码
ProxyHost string `field:"proxyHost"` // 代理的主机名 ProxyHost string `field:"proxyHost"` // 代理的主机名
IsBreak uint8 `field:"isBreak"` // 是否终止解析 IsBreak bool `field:"isBreak"` // 是否终止解析
WithQuery uint8 `field:"withQuery"` // 是否保留URI参数 WithQuery uint8 `field:"withQuery"` // 是否保留URI参数
Conds string `field:"conds"` // 匹配条件 Conds dbs.JSON `field:"conds"` // 匹配条件
} }
type HTTPRewriteRuleOperator struct { type HTTPRewriteRuleOperator struct {

View File

@@ -3,6 +3,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
@@ -94,14 +95,14 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPWebConfig{} var config = &serverconfigs.HTTPWebConfig{}
config.Id = webId config.Id = webId
config.IsOn = web.IsOn == 1 config.IsOn = web.IsOn
// root // root
if IsNotNull(web.Root) { if IsNotNull(web.Root) {
rootConfig := &serverconfigs.HTTPRootConfig{} rootConfig := &serverconfigs.HTTPRootConfig{}
err = json.Unmarshal([]byte(web.Root), rootConfig) err = json.Unmarshal(web.Root, rootConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -111,7 +112,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// compression // compression
if IsNotNull(web.Compression) { if IsNotNull(web.Compression) {
compression := &serverconfigs.HTTPCompressionConfig{} compression := &serverconfigs.HTTPCompressionConfig{}
err = json.Unmarshal([]byte(web.Compression), compression) err = json.Unmarshal(web.Compression, compression)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -148,7 +149,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// charset // charset
if IsNotNull(web.Charset) { if IsNotNull(web.Charset) {
charsetConfig := &serverconfigs.HTTPCharsetConfig{} charsetConfig := &serverconfigs.HTTPCharsetConfig{}
err = json.Unmarshal([]byte(web.Charset), charsetConfig) err = json.Unmarshal(web.Charset, charsetConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -158,7 +159,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// headers // headers
if IsNotNull(web.RequestHeader) { if IsNotNull(web.RequestHeader) {
ref := &shared.HTTPHeaderPolicyRef{} ref := &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal([]byte(web.RequestHeader), ref) err = json.Unmarshal(web.RequestHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -177,7 +178,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if IsNotNull(web.ResponseHeader) { if IsNotNull(web.ResponseHeader) {
ref := &shared.HTTPHeaderPolicyRef{} ref := &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal([]byte(web.ResponseHeader), ref) err = json.Unmarshal(web.ResponseHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -197,7 +198,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// shutdown // shutdown
if IsNotNull(web.Shutdown) { if IsNotNull(web.Shutdown) {
shutdownConfig := &serverconfigs.HTTPShutdownConfig{} shutdownConfig := &serverconfigs.HTTPShutdownConfig{}
err = json.Unmarshal([]byte(web.Shutdown), shutdownConfig) err = json.Unmarshal(web.Shutdown, shutdownConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -207,7 +208,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// pages // pages
if IsNotNull(web.Pages) { if IsNotNull(web.Pages) {
pages := []*serverconfigs.HTTPPageConfig{} pages := []*serverconfigs.HTTPPageConfig{}
err = json.Unmarshal([]byte(web.Pages), &pages) err = json.Unmarshal(web.Pages, &pages)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -226,7 +227,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 访问日志 // 访问日志
if IsNotNull(web.AccessLog) { if IsNotNull(web.AccessLog) {
accessLogConfig := &serverconfigs.HTTPAccessLogRef{} accessLogConfig := &serverconfigs.HTTPAccessLogRef{}
err = json.Unmarshal([]byte(web.AccessLog), accessLogConfig) err = json.Unmarshal(web.AccessLog, accessLogConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -236,7 +237,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 统计配置 // 统计配置
if IsNotNull(web.Stat) { if IsNotNull(web.Stat) {
statRef := &serverconfigs.HTTPStatRef{} statRef := &serverconfigs.HTTPStatRef{}
err = json.Unmarshal([]byte(web.Stat), statRef) err = json.Unmarshal(web.Stat, statRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -246,7 +247,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 缓存配置 // 缓存配置
if IsNotNull(web.Cache) { if IsNotNull(web.Cache) {
cacheConfig := &serverconfigs.HTTPCacheConfig{} cacheConfig := &serverconfigs.HTTPCacheConfig{}
err = json.Unmarshal([]byte(web.Cache), &cacheConfig) err = json.Unmarshal(web.Cache, &cacheConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -258,7 +259,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 防火墙配置 // 防火墙配置
if IsNotNull(web.Firewall) { if IsNotNull(web.Firewall) {
firewallRef := &firewallconfigs.HTTPFirewallRef{} firewallRef := &firewallconfigs.HTTPFirewallRef{}
err = json.Unmarshal([]byte(web.Firewall), firewallRef) err = json.Unmarshal(web.Firewall, firewallRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -281,7 +282,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 路由规则 // 路由规则
if IsNotNull(web.Locations) { if IsNotNull(web.Locations) {
refs := []*serverconfigs.HTTPLocationRef{} refs := []*serverconfigs.HTTPLocationRef{}
err = json.Unmarshal([]byte(web.Locations), &refs) err = json.Unmarshal(web.Locations, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -299,7 +300,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 跳转 // 跳转
if IsNotNull(web.RedirectToHttps) { if IsNotNull(web.RedirectToHttps) {
redirectToHTTPSConfig := &serverconfigs.HTTPRedirectToHTTPSConfig{} redirectToHTTPSConfig := &serverconfigs.HTTPRedirectToHTTPSConfig{}
err = json.Unmarshal([]byte(web.RedirectToHttps), redirectToHTTPSConfig) err = json.Unmarshal(web.RedirectToHttps, redirectToHTTPSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -309,7 +310,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// Websocket // Websocket
if IsNotNull(web.Websocket) { if IsNotNull(web.Websocket) {
ref := &serverconfigs.HTTPWebsocketRef{} ref := &serverconfigs.HTTPWebsocketRef{}
err = json.Unmarshal([]byte(web.Websocket), ref) err = json.Unmarshal(web.Websocket, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -328,7 +329,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 重写规则 // 重写规则
if IsNotNull(web.RewriteRules) { if IsNotNull(web.RewriteRules) {
refs := []*serverconfigs.HTTPRewriteRef{} refs := []*serverconfigs.HTTPRewriteRef{}
err = json.Unmarshal([]byte(web.RewriteRules), &refs) err = json.Unmarshal(web.RewriteRules, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -347,7 +348,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 主机跳转 // 主机跳转
if IsNotNull(web.HostRedirects) { if IsNotNull(web.HostRedirects) {
redirects := []*serverconfigs.HTTPHostRedirectConfig{} redirects := []*serverconfigs.HTTPHostRedirectConfig{}
err = json.Unmarshal([]byte(web.HostRedirects), &redirects) err = json.Unmarshal(web.HostRedirects, &redirects)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -357,7 +358,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// Fastcgi // Fastcgi
if IsNotNull(web.Fastcgi) { if IsNotNull(web.Fastcgi) {
ref := &serverconfigs.HTTPFastcgiRef{} ref := &serverconfigs.HTTPFastcgiRef{}
err = json.Unmarshal([]byte(web.Fastcgi), ref) err = json.Unmarshal(web.Fastcgi, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -381,7 +382,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 认证 // 认证
if IsNotNull(web.Auth) { if IsNotNull(web.Auth) {
authConfig := &serverconfigs.HTTPAuthConfig{} authConfig := &serverconfigs.HTTPAuthConfig{}
err = json.Unmarshal([]byte(web.Auth), authConfig) err = json.Unmarshal(web.Auth, authConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -402,7 +403,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// WebP // WebP
if IsNotNull(web.Webp) { if IsNotNull(web.Webp) {
var webpConfig = &serverconfigs.WebPImageConfig{} var webpConfig = &serverconfigs.WebPImageConfig{}
err = json.Unmarshal([]byte(web.Webp), webpConfig) err = json.Unmarshal(web.Webp, webpConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -412,7 +413,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// RemoteAddr // RemoteAddr
if IsNotNull(web.RemoteAddr) { if IsNotNull(web.RemoteAddr) {
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{} var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{}
err = json.Unmarshal([]byte(web.RemoteAddr), remoteAddrConfig) err = json.Unmarshal(web.RemoteAddr, remoteAddrConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -426,7 +427,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if len(web.RequestLimit) > 0 { if len(web.RequestLimit) > 0 {
var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{} var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{}
if len(web.RequestLimit) > 0 { if len(web.RequestLimit) > 0 {
err = json.Unmarshal([]byte(web.RequestLimit), requestLimitConfig) err = json.Unmarshal(web.RequestLimit, requestLimitConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -438,7 +439,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if len(web.RequestScripts) > 0 { if len(web.RequestScripts) > 0 {
var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{} var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{}
if len(web.RequestScripts) > 0 { if len(web.RequestScripts) > 0 {
err = json.Unmarshal([]byte(web.RequestScripts), requestScriptsConfig) err = json.Unmarshal(web.RequestScripts, requestScriptsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -446,6 +447,16 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
} }
} }
// UAM
if teaconst.IsPlus && IsNotNull(web.Uam) {
var uamConfig = &serverconfigs.UAMConfig{}
err = json.Unmarshal(web.Uam, uamConfig)
if err != nil {
return nil, err
}
config.UAM = uamConfig
}
if cacheMap != nil { if cacheMap != nil {
cacheMap.Put(cacheKey, config) cacheMap.Put(cacheKey, config)
} }
@@ -1168,6 +1179,35 @@ func (this *HTTPWebDAO) FindWebRequestScripts(tx *dbs.Tx, webId int64) (*serverc
return config, nil return config, nil
} }
// UpdateWebUAM 开启UAM
func (this *HTTPWebDAO) UpdateWebUAM(tx *dbs.Tx, webId int64, uamConfig *serverconfigs.UAMConfig) error {
if uamConfig == nil {
return nil
}
configJSON, err := json.Marshal(uamConfig)
if err != nil {
return err
}
err = this.Query(tx).
Pk(webId).
Set("uam", configJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
// FindWebUAM 查找服务的UAM配置
func (this *HTTPWebDAO) FindWebUAM(tx *dbs.Tx, webId int64) ([]byte, error) {
return this.Query(tx).
Pk(webId).
Result("uam").
FindJSONCol()
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error { func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
// server // server

View File

@@ -1,40 +1,43 @@
package models package models
import "github.com/iwind/TeaGo/dbs"
// HTTPWeb HTTP Web // HTTPWeb HTTP Web
type HTTPWeb struct { type HTTPWeb struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
TemplateId uint32 `field:"templateId"` // 模版ID TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Root string `field:"root"` // 根目录 Root dbs.JSON `field:"root"` // 根目录
Charset string `field:"charset"` // 字符集 Charset dbs.JSON `field:"charset"` // 字符集
Shutdown string `field:"shutdown"` // 临时关闭页面配置 Shutdown dbs.JSON `field:"shutdown"` // 临时关闭页面配置
Pages string `field:"pages"` // 特殊页面 Pages dbs.JSON `field:"pages"` // 特殊页面
RedirectToHttps string `field:"redirectToHttps"` // 跳转到HTTPS设置 RedirectToHttps dbs.JSON `field:"redirectToHttps"` // 跳转到HTTPS设置
Indexes string `field:"indexes"` // 首页文件列表 Indexes dbs.JSON `field:"indexes"` // 首页文件列表
MaxRequestBodySize string `field:"maxRequestBodySize"` // 最大允许的请求内容尺寸 MaxRequestBodySize dbs.JSON `field:"maxRequestBodySize"` // 最大允许的请求内容尺寸
RequestHeader string `field:"requestHeader"` // 请求Header配置 RequestHeader dbs.JSON `field:"requestHeader"` // 请求Header配置
ResponseHeader string `field:"responseHeader"` // 响应Header配置 ResponseHeader dbs.JSON `field:"responseHeader"` // 响应Header配置
AccessLog string `field:"accessLog"` // 访问日志配置 AccessLog dbs.JSON `field:"accessLog"` // 访问日志配置
Stat string `field:"stat"` // 统计配置 Stat dbs.JSON `field:"stat"` // 统计配置
Gzip string `field:"gzip"` // Gzip配置v0.3.2弃用) Gzip dbs.JSON `field:"gzip"` // Gzip配置v0.3.2弃用)
Compression string `field:"compression"` // 压缩配置 Compression dbs.JSON `field:"compression"` // 压缩配置
Cache string `field:"cache"` // 缓存配置 Cache dbs.JSON `field:"cache"` // 缓存配置
Firewall string `field:"firewall"` // 防火墙设置 Firewall dbs.JSON `field:"firewall"` // 防火墙设置
Locations string `field:"locations"` // 路由规则配置 Locations dbs.JSON `field:"locations"` // 路由规则配置
Websocket string `field:"websocket"` // Websocket设置 Websocket dbs.JSON `field:"websocket"` // Websocket设置
RewriteRules string `field:"rewriteRules"` // 重写规则配置 RewriteRules dbs.JSON `field:"rewriteRules"` // 重写规则配置
HostRedirects string `field:"hostRedirects"` // 域名跳转 HostRedirects dbs.JSON `field:"hostRedirects"` // 域名跳转
Fastcgi string `field:"fastcgi"` // Fastcgi配置 Fastcgi dbs.JSON `field:"fastcgi"` // Fastcgi配置
Auth string `field:"auth"` // 认证策略配置 Auth dbs.JSON `field:"auth"` // 认证策略配置
Webp string `field:"webp"` // WebP配置 Webp dbs.JSON `field:"webp"` // WebP配置
RemoteAddr string `field:"remoteAddr"` // 客户端IP配置 RemoteAddr dbs.JSON `field:"remoteAddr"` // 客户端IP配置
MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠 MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠
RequestLimit string `field:"requestLimit"` // 请求限制 RequestLimit dbs.JSON `field:"requestLimit"` // 请求限制
RequestScripts string `field:"requestScripts"` // 请求脚本 RequestScripts dbs.JSON `field:"requestScripts"` // 请求脚本
Uam dbs.JSON `field:"uam"` // UAM设置
} }
type HTTPWebOperator struct { type HTTPWebOperator struct {
@@ -71,6 +74,7 @@ type HTTPWebOperator struct {
MergeSlashes interface{} // 是否合并路径中的斜杠 MergeSlashes interface{} // 是否合并路径中的斜杠
RequestLimit interface{} // 请求限制 RequestLimit interface{} // 请求限制
RequestScripts interface{} // 请求脚本 RequestScripts interface{} // 请求脚本
Uam interface{} // UAM设置
} }
func NewHTTPWebOperator() *HTTPWebOperator { func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -37,7 +37,7 @@ func init() {
}) })
} }
// 启用条目 // EnableHTTPWebsocket 启用条目
func (this *HTTPWebsocketDAO) EnableHTTPWebsocket(tx *dbs.Tx, id int64) error { func (this *HTTPWebsocketDAO) EnableHTTPWebsocket(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -46,7 +46,7 @@ func (this *HTTPWebsocketDAO) EnableHTTPWebsocket(tx *dbs.Tx, id int64) error {
return err return err
} }
// 禁用条目 // DisableHTTPWebsocket 禁用条目
func (this *HTTPWebsocketDAO) DisableHTTPWebsocket(tx *dbs.Tx, websocketId int64) error { func (this *HTTPWebsocketDAO) DisableHTTPWebsocket(tx *dbs.Tx, websocketId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(websocketId). Pk(websocketId).
@@ -58,7 +58,7 @@ func (this *HTTPWebsocketDAO) DisableHTTPWebsocket(tx *dbs.Tx, websocketId int64
return this.NotifyUpdate(tx, websocketId) return this.NotifyUpdate(tx, websocketId)
} }
// 查找启用中的条目 // FindEnabledHTTPWebsocket 查找启用中的条目
func (this *HTTPWebsocketDAO) FindEnabledHTTPWebsocket(tx *dbs.Tx, id int64) (*HTTPWebsocket, error) { func (this *HTTPWebsocketDAO) FindEnabledHTTPWebsocket(tx *dbs.Tx, id int64) (*HTTPWebsocket, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Pk(id).
@@ -70,7 +70,7 @@ func (this *HTTPWebsocketDAO) FindEnabledHTTPWebsocket(tx *dbs.Tx, id int64) (*H
return result.(*HTTPWebsocket), err return result.(*HTTPWebsocket), err
} }
// 组合配置 // ComposeWebsocketConfig 组合配置
func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int64) (*serverconfigs.HTTPWebsocketConfig, error) { func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int64) (*serverconfigs.HTTPWebsocketConfig, error) {
websocket, err := this.FindEnabledHTTPWebsocket(tx, websocketId) websocket, err := this.FindEnabledHTTPWebsocket(tx, websocketId)
if err != nil { if err != nil {
@@ -81,12 +81,12 @@ func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int
} }
config := &serverconfigs.HTTPWebsocketConfig{} config := &serverconfigs.HTTPWebsocketConfig{}
config.Id = int64(websocket.Id) config.Id = int64(websocket.Id)
config.IsOn = websocket.IsOn == 1 config.IsOn = websocket.IsOn
config.AllowAllOrigins = websocket.AllowAllOrigins == 1 config.AllowAllOrigins = websocket.AllowAllOrigins == 1
if IsNotNull(websocket.AllowedOrigins) { if IsNotNull(websocket.AllowedOrigins) {
origins := []string{} origins := []string{}
err = json.Unmarshal([]byte(websocket.AllowedOrigins), &origins) err = json.Unmarshal(websocket.AllowedOrigins, &origins)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -95,7 +95,7 @@ func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int
if IsNotNull(websocket.HandshakeTimeout) { if IsNotNull(websocket.HandshakeTimeout) {
duration := &shared.TimeDuration{} duration := &shared.TimeDuration{}
err = json.Unmarshal([]byte(websocket.HandshakeTimeout), duration) err = json.Unmarshal(websocket.HandshakeTimeout, duration)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -108,7 +108,7 @@ func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int
return config, nil return config, nil
} }
// 创建Websocket配置 // CreateWebsocket 创建Websocket配置
func (this *HTTPWebsocketDAO) CreateWebsocket(tx *dbs.Tx, handshakeTimeoutJSON []byte, allowAllOrigins bool, allowedOrigins []string, requestSameOrigin bool, requestOrigin string) (websocketId int64, err error) { func (this *HTTPWebsocketDAO) CreateWebsocket(tx *dbs.Tx, handshakeTimeoutJSON []byte, allowAllOrigins bool, allowedOrigins []string, requestSameOrigin bool, requestOrigin string) (websocketId int64, err error) {
op := NewHTTPWebsocketOperator() op := NewHTTPWebsocketOperator()
op.IsOn = true op.IsOn = true
@@ -130,7 +130,7 @@ func (this *HTTPWebsocketDAO) CreateWebsocket(tx *dbs.Tx, handshakeTimeoutJSON [
return types.Int64(op.Id), err return types.Int64(op.Id), err
} }
// 修改Websocket配置 // UpdateWebsocket 修改Websocket配置
func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, handshakeTimeoutJSON []byte, allowAllOrigins bool, allowedOrigins []string, requestSameOrigin bool, requestOrigin string) error { func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, handshakeTimeoutJSON []byte, allowAllOrigins bool, allowedOrigins []string, requestSameOrigin bool, requestOrigin string) error {
if websocketId <= 0 { if websocketId <= 0 {
return errors.New("invalid websocketId") return errors.New("invalid websocketId")
@@ -159,7 +159,7 @@ func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, han
return this.NotifyUpdate(tx, websocketId) return this.NotifyUpdate(tx, websocketId)
} }
// 通知更新 // NotifyUpdate 通知更新
func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error { func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId)
if err != nil { if err != nil {

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