Compare commits

..

60 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
123 changed files with 5575 additions and 788 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"
@@ -13,6 +14,7 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"io/ioutil"
"log" "log"
"os" "os"
) )
@@ -21,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 {
@@ -122,6 +124,43 @@ func main() {
fmt.Println("prepared statements count: " + types.String(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

27
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/TeaOSLab/EdgeAPI module github.com/TeaOSLab/EdgeAPI
go 1.16 go 1.18
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
@@ -12,9 +12,8 @@ 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-20220408064305-92be81dc2f7c 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 github.com/shirou/gopsutil/v3 v3.22.2
@@ -24,3 +23,25 @@ require (
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
)

8
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=
@@ -238,10 +237,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
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/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-20220322141208-22f88d04004d h1:e8fkTKras/RXQWECApM9fKlFWujjYjEClpshkmZmtYg= github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570 h1:zqz2FiMMkSHXWO1EsTRJDPTwX9xQ4uuyD5GAE4JGlhM=
github.com/iwind/TeaGo v0.0.0-20220322141208-22f88d04004d/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc= github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/TeaGo v0.0.0-20220408064305-92be81dc2f7c h1:ugjYZ74FJGWlfDKKraNgMyDTeS4vbXHe89JGUVQIJMo=
github.com/iwind/TeaGo v0.0.0-20220408064305-92be81dc2f7c/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=
@@ -559,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=

View File

@@ -44,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

@@ -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
@@ -111,7 +116,7 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
} }
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)
@@ -121,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

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

View File

@@ -58,15 +58,22 @@ func (this *APINodeDAO) EnableAPINode(tx *dbs.Tx, id int64) error {
} }
// 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()
if err != nil { if err != nil {
return err return err
} }
return this.NotifyUpdate(tx, id)
err = this.NotifyUpdate(tx, nodeId)
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleAPI, nodeId)
} }
// FindEnabledAPINode 查找启用中的条目 // FindEnabledAPINode 查找启用中的条目

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

@@ -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

@@ -107,7 +107,7 @@ 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, domain 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)").
@@ -119,12 +119,16 @@ func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int6
query.Param("domain", 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, domain 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)").
@@ -134,6 +138,9 @@ func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, u
query.Where("id IN (SELECT providerId FROM " + SharedDNSDomainDAO.Table + " WHERE state=1 AND name=:domain)") query.Where("id IN (SELECT providerId FROM " + SharedDNSDomainDAO.Table + " WHERE state=1 AND name=:domain)")
query.Param("domain", domain) query.Param("domain", domain)
} }
if len(providerType) > 0 {
query.Attr("type", providerType)
}
_, err = query. _, err = query.
State(DNSProviderStateEnabled). State(DNSProviderStateEnabled).
Offset(offset). Offset(offset).

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"` // 文件名
@@ -19,6 +20,7 @@ type File struct {
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

@@ -395,9 +395,14 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
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 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{}
@@ -509,13 +514,25 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
isSpecialKeyword = true 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]))
// TODO 处理剩余的关键词
} else if statusPrefixReg.MatchString(keyword) { // status:200 } else if statusPrefixReg.MatchString(keyword) { // status:200
isSpecialKeyword = true isSpecialKeyword = true
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) {
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 } else if urlReg.MatchString(keyword) { // https://xxx/yyy
u, err := url.Parse(keyword) u, err := url.Parse(keyword)
if err == nil { if err == nil {

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

@@ -117,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
@@ -131,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)
@@ -160,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)
@@ -207,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
} }
@@ -268,6 +286,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
inboundJSON []byte, inboundJSON []byte,
outboundJSON []byte, outboundJSON []byte,
blockOptionsJSON []byte, blockOptionsJSON []byte,
captchaOptionsJSON []byte,
mode firewallconfigs.FirewallMode, mode firewallconfigs.FirewallMode,
useLocalFirewall bool, useLocalFirewall bool,
synFloodConfig *firewallconfigs.SYNFloodConfig, synFloodConfig *firewallconfigs.SYNFloodConfig,
@@ -275,7 +294,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
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
@@ -291,9 +310,12 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
} 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)
@@ -456,7 +478,7 @@ 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(policy.BlockOptions, blockAction) err = json.Unmarshal(policy.BlockOptions, blockAction)
if err != nil { if err != nil {
return config, err return config, err
@@ -464,6 +486,16 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
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 IsNotNull(policy.SynFlood) { if IsNotNull(policy.SynFlood) {
var synFloodConfig = &firewallconfigs.SYNFloodConfig{} var synFloodConfig = &firewallconfigs.SYNFloodConfig{}
@@ -526,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().
@@ -544,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

@@ -18,6 +18,7 @@ type HTTPFirewallPolicy struct {
Inbound dbs.JSON `field:"inbound"` // 入站规则 Inbound dbs.JSON `field:"inbound"` // 入站规则
Outbound dbs.JSON `field:"outbound"` // 出站规则 Outbound dbs.JSON `field:"outbound"` // 出站规则
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项 BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
Mode string `field:"mode"` // 模式 Mode string `field:"mode"` // 模式
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙 UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置 SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
@@ -39,6 +40,7 @@ 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防御设置

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"
@@ -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

@@ -37,6 +37,7 @@ type HTTPWeb struct {
MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠 MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠
RequestLimit dbs.JSON `field:"requestLimit"` // 请求限制 RequestLimit dbs.JSON `field:"requestLimit"` // 请求限制
RequestScripts dbs.JSON `field:"requestScripts"` // 请求脚本 RequestScripts dbs.JSON `field:"requestScripts"` // 请求脚本
Uam dbs.JSON `field:"uam"` // UAM设置
} }
type HTTPWebOperator struct { type HTTPWebOperator struct {
@@ -73,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

@@ -93,6 +93,71 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
return this.NotifyUpdate(tx, id) return this.NotifyUpdate(tx, id)
} }
// DisableIPItemsWithIP 禁用某个IP相关条目
func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, userId int64, listId int64) error {
if len(ipFrom) == 0 {
return errors.New("invalid 'ipFrom'")
}
var query = this.Query(tx).
Result("id", "listId").
Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo).
State(IPItemStateEnabled)
if listId > 0 {
if userId > 0 {
err := SharedIPListDAO.CheckUserIPList(tx, userId, listId)
if err != nil {
return err
}
}
query.Attr("listId", listId)
}
ones, err := query.FindAll()
if err != nil {
return err
}
var itemIds = []int64{}
for _, one := range ones {
var item = one.(*IPItem)
var itemId = int64(item.Id)
var itemListId = int64(item.ListId)
if itemListId != listId && userId > 0 {
err = SharedIPListDAO.CheckUserIPList(tx, userId, itemListId)
if err != nil {
// ignore error
continue
}
}
itemIds = append(itemIds, itemId)
}
for _, itemId := range itemIds {
version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(itemId).
Set("state", IPItemStateDisabled).
Set("version", version).
Update()
if err != nil {
return err
}
}
if len(itemIds) > 0 {
return this.NotifyUpdate(tx, itemIds[len(itemIds)-1])
}
return nil
}
// DisableIPItemsWithListId 禁用某个IP名单内的所有IP // DisableIPItemsWithListId 禁用某个IP名单内的所有IP
func (this *IPItemDAO) DisableIPItemsWithListId(tx *dbs.Tx, listId int64) error { func (this *IPItemDAO) DisableIPItemsWithListId(tx *dbs.Tx, listId int64) error {
for { for {
@@ -142,14 +207,35 @@ func (this *IPItemDAO) FindEnabledIPItem(tx *dbs.Tx, id int64) (*IPItem, error)
// DeleteOldItem 根据IP删除以前的旧记录 // DeleteOldItem 根据IP删除以前的旧记录
func (this *IPItemDAO) DeleteOldItem(tx *dbs.Tx, listId int64, ipFrom string, ipTo string) error { func (this *IPItemDAO) DeleteOldItem(tx *dbs.Tx, listId int64, ipFrom string, ipTo string) error {
_, err := this.Query(tx). ones, err := this.Query(tx).
ResultPk().
UseIndex("ipFrom"). UseIndex("ipFrom").
Attr("listId", listId). Attr("listId", listId).
Attr("ipFrom", ipFrom). Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo). Attr("ipTo", ipTo).
Delete() Set("state", IPItemStateEnabled).
// 这里不通知更新 FindAll()
return err if err != nil {
return err
}
for _, one := range ones {
var itemId = int64(one.(*IPItem).Id)
version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil {
return err
}
err = this.Query(tx).
Pk(itemId).
Set("version", version).
Set("state", IPItemStateDisabled).
UpdateQuickly()
if err != nil {
return err
}
}
return nil
} }
// CreateIPItem 创建IP // CreateIPItem 创建IP
@@ -202,6 +288,8 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
} }
op.State = IPItemStateEnabled op.State = IPItemStateEnabled
op.UpdatedAt = time.Now().Unix()
err = this.Save(tx, op) err = this.Save(tx, op)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -453,7 +541,7 @@ func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error {
func (this *IPItemDAO) CleanExpiredIPItems(tx *dbs.Tx) error { func (this *IPItemDAO) CleanExpiredIPItems(tx *dbs.Tx) error {
// 删除 N 天之前过期的数据 // 删除 N 天之前过期的数据
_, err := this.Query(tx). _, err := this.Query(tx).
Where("expiredAt<=:timestamp"). Where("(createdAt<=:timestamp AND updatedAt<=:timestamp)").
State(IPItemStateDisabled). State(IPItemStateDisabled).
Param("timestamp", time.Now().Unix()-7*86400). // N 天之前过期的 Param("timestamp", time.Now().Unix()-7*86400). // N 天之前过期的
Limit(10000). // 限制条数,防止数量过多导致超时 Limit(10000). // 限制条数,防止数量过多导致超时

View File

@@ -1,6 +1,7 @@
package models package models_test
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -14,7 +15,7 @@ func TestIPItemDAO_NotifyClustersUpdate(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedIPItemDAO.NotifyUpdate(tx, 28) err := models.SharedIPItemDAO.NotifyUpdate(tx, 28)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -25,7 +26,7 @@ func TestIPItemDAO_DisableIPItemsWithListId(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedIPItemDAO.DisableIPItemsWithListId(tx, 67) err := models.SharedIPItemDAO.DisableIPItemsWithListId(tx, 67)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -36,7 +37,7 @@ func TestIPItemDAO_ListIPItemsAfterVersion(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
_, err := SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100) _, err := models.SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -47,10 +48,10 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
var dao = NewIPItemDAO() var dao = models.NewIPItemDAO()
var n = 10 var n = 10
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0) itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -62,3 +63,14 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
} }
t.Log("ok") t.Log("ok")
} }
func TestIPItemDAO_DisableIPItemsWithIP(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
err := models.SharedIPItemDAO.DisableIPItemsWithIP(tx, "192.168.1.100", "", 0, 0)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -138,10 +138,11 @@ func (this *IPListDAO) FindIPListCacheable(tx *dbs.Tx, listId int64) (*IPList, e
} }
// CreateIPList 创建名单 // CreateIPList 创建名单
func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte, description string, isPublic bool, isGlobal bool) (int64, error) { func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, serverId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte, description string, isPublic bool, isGlobal bool) (int64, error) {
op := NewIPListOperator() var op = NewIPListOperator()
op.IsOn = true op.IsOn = true
op.UserId = userId op.UserId = userId
op.ServerId = serverId
op.State = IPListStateEnabled op.State = IPListStateEnabled
op.Type = listType op.Type = listType
op.Name = name op.Name = name
@@ -189,26 +190,25 @@ func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) e
return ErrNotFound return ErrNotFound
} }
ok, err := this.Query(tx). // 获取名单信息
listOne, err := this.Query(tx).
Pk(listId). Pk(listId).
Attr("userId", userId). Result("userId", "serverId").
Exist() Find()
if err != nil { if err != nil {
return err return err
} }
if ok { if listOne == nil {
return ErrNotFound
}
var list = listOne.(*IPList)
if int64(list.UserId) == userId {
return nil return nil
} }
// 检查是否被用户的服务所使用 var serverId = int64(list.ServerId)
policyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId) if serverId > 0 {
if err != nil { return SharedServerDAO.CheckUserServer(tx, userId, serverId)
return err
}
for _, policyId := range policyIds {
if SharedHTTPFirewallPolicyDAO.CheckUserFirewallPolicy(tx, userId, policyId) == nil {
return nil
}
} }
return ErrNotFound return ErrNotFound

View File

@@ -20,6 +20,39 @@ func TestIPListDAO_IncreaseVersion(t *testing.T) {
t.Log("version:", version) t.Log("version:", version)
} }
func TestIPListDAO_CheckUserIPList(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
if err == ErrNotFound {
t.Log("not found")
} else {
t.Log(err)
}
}
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
if err == ErrNotFound {
t.Log("not found")
} else {
t.Log(err)
}
}
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
if err == ErrNotFound {
t.Log("not found")
} else {
t.Log(err)
}
}
}
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) { func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
runtime.GOMAXPROCS(1) runtime.GOMAXPROCS(1)
@@ -32,3 +65,4 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
_, _ = dao.IncreaseVersion(tx) _, _ = dao.IncreaseVersion(tx)
} }
} }

View File

@@ -9,6 +9,7 @@ type IPList struct {
Type string `field:"type"` // 类型 Type string `field:"type"` // 类型
AdminId uint32 `field:"adminId"` // 用户ID AdminId uint32 `field:"adminId"` // 用户ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
Name string `field:"name"` // 列表名 Name string `field:"name"` // 列表名
Code string `field:"code"` // 代号 Code string `field:"code"` // 代号
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
@@ -26,6 +27,7 @@ type IPListOperator struct {
Type interface{} // 类型 Type interface{} // 类型
AdminId interface{} // 用户ID AdminId interface{} // 用户ID
UserId interface{} // 用户ID UserId interface{} // 用户ID
ServerId interface{} // 服务ID
Name interface{} // 列表名 Name interface{} // 列表名
Code interface{} // 代号 Code interface{} // 代号
State interface{} // 状态 State interface{} // 状态

View File

@@ -90,9 +90,7 @@ func (this *MetricStatDAO) CreateStat(tx *dbs.Tx, hash string, clusterId int64,
"value": value, "value": value,
}) })
if err != nil { if err != nil {
// 忽略 Error 1213: Deadlock found 错误 if this.canIgnore(err) {
mysqlErr, ok := err.(*mysql.MySQLError)
if ok && mysqlErr.Number == 1213 {
return nil return nil
} }
return err return err
@@ -135,6 +133,9 @@ func (this *MetricStatDAO) DeleteNodeItemStats(tx *dbs.Tx, nodeId int64, serverI
Attr("itemId", itemId). Attr("itemId", itemId).
Attr("time", time). Attr("time", time).
Delete() Delete()
if this.canIgnore(err) {
return nil
}
return err return err
} }
@@ -690,7 +691,6 @@ func (this *MetricStatDAO) Clean(tx *dbs.Tx) error {
Table(table). Table(table).
Attr("itemId", item.Id). Attr("itemId", item.Id).
Lte("createdDay", expiresDay). Lte("createdDay", expiresDay).
UseIndex("createdDay").
Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作 Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作
Delete() Delete()
return err return err
@@ -751,3 +751,18 @@ func (this *MetricStatDAO) mergeStats(stats []*MetricStat) (result []*MetricStat
} }
return result return result
} }
// 检查错误是否可以忽略
func (this *MetricStatDAO) canIgnore(err error) bool {
if err == nil {
return true
}
// 忽略 Error 1213: Deadlock found 错误
mysqlErr, ok := err.(*mysql.MySQLError)
if ok && mysqlErr.Number == 1213 {
return true
}
return false
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/go-sql-driver/mysql"
_ "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"
@@ -55,7 +56,7 @@ func init() {
// UpdateSum 更新统计数据 // UpdateSum 更新统计数据
func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int64, serverId int64, time string, itemId int64, version int32, count int64, total float32) error { func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int64, serverId int64, time string, itemId int64, version int32, count int64, total float32) error {
return this.Query(tx). err := this.Query(tx).
Table(this.partialTable(serverId)). Table(this.partialTable(serverId)).
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId, "clusterId": clusterId,
@@ -71,6 +72,10 @@ func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int6
"count": count, "count": count,
"total": total, "total": total,
}) })
if this.canIgnore(err) {
return nil
}
return err
} }
// FindNodeServerSum 查找某个服务在某个节点上的统计数据 // FindNodeServerSum 查找某个服务在某个节点上的统计数据
@@ -232,7 +237,6 @@ func (this *MetricSumStatDAO) Clean(tx *dbs.Tx) error {
Attr("itemId", item.Id). Attr("itemId", item.Id).
Where("(createdDay IS NULL OR createdDay<:day)"). Where("(createdDay IS NULL OR createdDay<:day)").
Param("day", expiresDay). Param("day", expiresDay).
UseIndex("createdDay").
Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作 Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作
Delete() Delete()
return err return err
@@ -277,3 +281,18 @@ func (this *MetricSumStatDAO) runBatch(f func(table string, locker *sync.Mutex)
wg.Wait() wg.Wait()
return resultErr return resultErr
} }
// 检查错误是否可以忽略
func (this *MetricSumStatDAO) canIgnore(err error) bool {
if err == nil {
return true
}
// 忽略 Error 1213: Deadlock found 错误
mysqlErr, ok := err.(*mysql.MySQLError)
if ok && mysqlErr.Number == 1213 {
return true
}
return false
}

View File

@@ -47,12 +47,17 @@ func (this *MonitorNodeDAO) EnableMonitorNode(tx *dbs.Tx, id int64) error {
} }
// DisableMonitorNode 禁用条目 // DisableMonitorNode 禁用条目
func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, id int64) error { func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", MonitorNodeStateDisabled). Set("state", MonitorNodeStateDisabled).
Update() Update()
return err if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleMonitor, nodeId)
} }
// FindEnabledMonitorNode 查找启用中的条目 // FindEnabledMonitorNode 查找启用中的条目

View File

@@ -214,7 +214,7 @@ func (this *NSRouteDAO) FindAllEnabledRoutes(tx *dbs.Tx, clusterId int64, domain
State(NSRouteStateEnabled). State(NSRouteStateEnabled).
Slice(&result). Slice(&result).
Desc("order"). Desc("order").
DescPk() AscPk()
if clusterId > 0 { if clusterId > 0 {
query.Attr("clusterId", clusterId) query.Attr("clusterId", clusterId)
} else { } else {

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
_ "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"
@@ -141,10 +142,11 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// DNS设置 // DNS设置
op.DnsDomainId = dnsDomainId op.DnsDomainId = dnsDomainId
op.DnsName = dnsName op.DnsName = dnsName
dnsConfig := &dnsconfigs.ClusterDNSConfig{ var dnsConfig = &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: true, NodesAutoSync: true,
ServersAutoSync: true, ServersAutoSync: true,
CNameRecords: []string{}, CNameRecords: []string{},
CNameAsDomain: true,
TTL: 0, TTL: 0,
} }
dnsJSON, err := json.Marshal(dnsConfig) dnsJSON, err := json.Marshal(dnsConfig)
@@ -180,7 +182,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
} }
// UpdateCluster 修改集群 // UpdateCluster 修改集群
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, nodeTCPMaxConnections int32, autoOpenPorts bool) error { func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool) error {
if clusterId <= 0 { if clusterId <= 0 {
return errors.New("invalid clusterId") return errors.New("invalid clusterId")
} }
@@ -195,11 +197,6 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
nodeMaxThreads = 0 nodeMaxThreads = 0
} }
op.NodeMaxThreads = nodeMaxThreads op.NodeMaxThreads = nodeMaxThreads
if nodeTCPMaxConnections < 0 {
nodeTCPMaxConnections = 0
}
op.NodeTCPMaxConnections = nodeTCPMaxConnections
op.AutoOpenPorts = autoOpenPorts op.AutoOpenPorts = autoOpenPorts
err := this.Save(tx, op) err := this.Save(tx, op)
@@ -467,7 +464,7 @@ func (this *NodeClusterDAO) ExistClusterDNSName(tx *dbs.Tx, dnsName string, excl
} }
// UpdateClusterDNS 修改集群DNS相关信息 // UpdateClusterDNS 修改集群DNS相关信息
func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsName string, dnsDomainId int64, nodesAutoSync bool, serversAutoSync bool, cnameRecords []string, ttl int32) error { func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsName string, dnsDomainId int64, nodesAutoSync bool, serversAutoSync bool, cnameRecords []string, ttl int32, cnameAsDomain bool) error {
if clusterId <= 0 { if clusterId <= 0 {
return errors.New("invalid clusterId") return errors.New("invalid clusterId")
} }
@@ -507,6 +504,7 @@ func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsNam
ServersAutoSync: serversAutoSync, ServersAutoSync: serversAutoSync,
CNameRecords: cnameRecords, CNameRecords: cnameRecords,
TTL: ttl, TTL: ttl,
CNameAsDomain: cnameAsDomain,
} }
dnsJSON, err := json.Marshal(dnsConfig) dnsJSON, err := json.Marshal(dnsConfig)
if err != nil { if err != nil {
@@ -922,7 +920,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx). cluster, err := this.Query(tx).
Pk(clusterId). Pk(clusterId).
State(NodeClusterStateEnabled). State(NodeClusterStateEnabled).
Result("timeZone", "nodeMaxThreads", "nodeTCPMaxConnections", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "isOn"). Result("id", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "isOn", "ddosProtection").
Find() Find()
if err != nil || cluster == nil { if err != nil || cluster == nil {
return nil, err return nil, err
@@ -992,6 +990,104 @@ func (this *NodeClusterDAO) FindClusterWebPPolicy(tx *dbs.Tx, clusterId int64, c
return policy, nil return policy, nil
} }
// UpdateClusterUAMPolicy 修改UAM设置
func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64, uamPolicy *nodeconfigs.UAMPolicy) error {
if uamPolicy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("uam", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, clusterId)
}
uamPolicyJSON, err := json.Marshal(uamPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("uam", uamPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, clusterId)
}
// FindClusterUAMPolicy 查询设置
func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) {
var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.UAMPolicy), nil
}
}
uamJSON, err := this.Query(tx).
Pk(clusterId).
Result("uam").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(uamJSON) {
return nodeconfigs.DefaultUAMPolicy, nil
}
var policy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(uamJSON, policy)
if err != nil {
return nil, err
}
return policy, nil
}
// FindClusterDDoSProtection 获取集群的DDoS设置
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx).
Result("ddosProtection").
Pk(clusterId).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*NodeCluster).DecodeDDoSProtection(), nil
}
// UpdateClusterDDoSProtection 设置集群的DDOS设置
func (this *NodeClusterDAO) UpdateClusterDDoSProtection(tx *dbs.Tx, clusterId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if clusterId <= 0 {
return ErrNotFound
}
var op = NewNodeClusterOperator()
op.Id = clusterId
if ddosProtection == nil {
op.DdosProtection = "{}"
} else {
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return err
}
op.DdosProtection = ddosProtectionJSON
}
err := this.Save(tx, op)
if err != nil {
return err
}
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeDDosProtectionChanged)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error { func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged) return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)

View File

@@ -4,69 +4,71 @@ import "github.com/iwind/TeaGo/dbs"
// NodeCluster 节点集群 // NodeCluster 节点集群
type NodeCluster struct { type NodeCluster 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 bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
UseAllAPINodes uint8 `field:"useAllAPINodes"` // 是否使用所有API节点 UseAllAPINodes uint8 `field:"useAllAPINodes"` // 是否使用所有API节点
ApiNodes dbs.JSON `field:"apiNodes"` // 使用的API节点 ApiNodes dbs.JSON `field:"apiNodes"` // 使用的API节点
InstallDir string `field:"installDir"` // 安装目录 InstallDir string `field:"installDir"` // 安装目录
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
GrantId uint32 `field:"grantId"` // 默认认证方式 GrantId uint32 `field:"grantId"` // 默认认证方式
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
AutoRegister uint8 `field:"autoRegister"` // 是否开启自动注册 AutoRegister uint8 `field:"autoRegister"` // 是否开启自动注册
UniqueId string `field:"uniqueId"` // 唯一ID UniqueId string `field:"uniqueId"` // 唯一ID
Secret string `field:"secret"` // 密钥 Secret string `field:"secret"` // 密钥
HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查 HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查
DnsName string `field:"dnsName"` // DNS名称 DnsName string `field:"dnsName"` // DNS名称
DnsDomainId uint32 `field:"dnsDomainId"` // 域名ID DnsDomainId uint32 `field:"dnsDomainId"` // 域名ID
Dns dbs.JSON `field:"dns"` // DNS配置 Dns dbs.JSON `field:"dns"` // DNS配置
Toa dbs.JSON `field:"toa"` // TOA配置 Toa dbs.JSON `field:"toa"` // TOA配置
CachePolicyId uint32 `field:"cachePolicyId"` // 缓存策略ID CachePolicyId uint32 `field:"cachePolicyId"` // 缓存策略ID
HttpFirewallPolicyId uint32 `field:"httpFirewallPolicyId"` // WAF策略ID HttpFirewallPolicyId uint32 `field:"httpFirewallPolicyId"` // WAF策略ID
AccessLog dbs.JSON `field:"accessLog"` // 访问日志设置 AccessLog dbs.JSON `field:"accessLog"` // 访问日志设置
SystemServices dbs.JSON `field:"systemServices"` // 系统服务设置 SystemServices dbs.JSON `field:"systemServices"` // 系统服务设置
TimeZone string `field:"timeZone"` // 时区 TimeZone string `field:"timeZone"` // 时区
NodeMaxThreads uint32 `field:"nodeMaxThreads"` // 节点最大线程数 NodeMaxThreads uint32 `field:"nodeMaxThreads"` // 节点最大线程数
NodeTCPMaxConnections uint32 `field:"nodeTCPMaxConnections"` // TCP最大连接数 DdosProtection dbs.JSON `field:"ddosProtection"` // DDOS端口
AutoOpenPorts uint8 `field:"autoOpenPorts"` // 是否自动尝试开放端口 AutoOpenPorts uint8 `field:"autoOpenPorts"` // 是否自动尝试开放端口
IsPinned bool `field:"isPinned"` // 是否置顶 IsPinned bool `field:"isPinned"` // 是否置顶
Webp dbs.JSON `field:"webp"` // WebP设置 Webp dbs.JSON `field:"webp"` // WebP设置
Uam dbs.JSON `field:"uam"` // UAM设置
} }
type NodeClusterOperator struct { type NodeClusterOperator struct {
Id interface{} // ID Id interface{} // ID
AdminId interface{} // 管理员ID AdminId interface{} // 管理员ID
UserId interface{} // 用户ID UserId interface{} // 用户ID
IsOn interface{} // 是否启用 IsOn interface{} // 是否启用
Name interface{} // 名称 Name interface{} // 名称
UseAllAPINodes interface{} // 是否使用所有API节点 UseAllAPINodes interface{} // 是否使用所有API节点
ApiNodes interface{} // 使用的API节点 ApiNodes interface{} // 使用的API节点
InstallDir interface{} // 安装目录 InstallDir interface{} // 安装目录
Order interface{} // 排序 Order interface{} // 排序
CreatedAt interface{} // 创建时间 CreatedAt interface{} // 创建时间
GrantId interface{} // 默认认证方式 GrantId interface{} // 默认认证方式
State interface{} // 状态 State interface{} // 状态
AutoRegister interface{} // 是否开启自动注册 AutoRegister interface{} // 是否开启自动注册
UniqueId interface{} // 唯一ID UniqueId interface{} // 唯一ID
Secret interface{} // 密钥 Secret interface{} // 密钥
HealthCheck interface{} // 健康检查 HealthCheck interface{} // 健康检查
DnsName interface{} // DNS名称 DnsName interface{} // DNS名称
DnsDomainId interface{} // 域名ID DnsDomainId interface{} // 域名ID
Dns interface{} // DNS配置 Dns interface{} // DNS配置
Toa interface{} // TOA配置 Toa interface{} // TOA配置
CachePolicyId interface{} // 缓存策略ID CachePolicyId interface{} // 缓存策略ID
HttpFirewallPolicyId interface{} // WAF策略ID HttpFirewallPolicyId interface{} // WAF策略ID
AccessLog interface{} // 访问日志设置 AccessLog interface{} // 访问日志设置
SystemServices interface{} // 系统服务设置 SystemServices interface{} // 系统服务设置
TimeZone interface{} // 时区 TimeZone interface{} // 时区
NodeMaxThreads interface{} // 节点最大线程数 NodeMaxThreads interface{} // 节点最大线程数
NodeTCPMaxConnections interface{} // TCP最大连接数 DdosProtection interface{} // DDOS端口
AutoOpenPorts interface{} // 是否自动尝试开放端口 AutoOpenPorts interface{} // 是否自动尝试开放端口
IsPinned interface{} // 是否置顶 IsPinned interface{} // 是否置顶
Webp interface{} // WebP设置 Webp interface{} // WebP设置
Uam interface{} // UAM设置
} }
func NewNodeClusterOperator() *NodeClusterOperator { func NewNodeClusterOperator() *NodeClusterOperator {

View File

@@ -3,6 +3,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
) )
// DecodeDNSConfig 解析DNS配置 // DecodeDNSConfig 解析DNS配置
@@ -12,12 +13,38 @@ func (this *NodeCluster) DecodeDNSConfig() (*dnsconfigs.ClusterDNSConfig, error)
return &dnsconfigs.ClusterDNSConfig{ return &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: false, NodesAutoSync: false,
ServersAutoSync: false, ServersAutoSync: false,
CNameAsDomain: true,
}, nil }, nil
} }
dnsConfig := &dnsconfigs.ClusterDNSConfig{} var dnsConfig = &dnsconfigs.ClusterDNSConfig{
CNameAsDomain: true,
}
err := json.Unmarshal(this.Dns, &dnsConfig) err := json.Unmarshal(this.Dns, &dnsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return dnsConfig, nil return dnsConfig, nil
} }
// DecodeDDoSProtection 解析DDOS Protection设置
func (this *NodeCluster) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
if IsNull(this.DdosProtection) {
return nil
}
var result = &ddosconfigs.ProtectionConfig{}
err := json.Unmarshal(this.DdosProtection, &result)
if err != nil {
// ignore err
}
return result
}
// HasDDoSProtection 检查是否有DDOS设置
func (this *NodeCluster) HasDDoSProtection() bool {
var config = this.DecodeDDoSProtection()
if config != nil {
return config.IsOn()
}
return false
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@@ -99,7 +100,8 @@ func (this *NodeDAO) DisableNode(tx *dbs.Tx, nodeId int64) (err error) {
return err return err
} }
return nil // 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleNode, nodeId)
} }
// FindEnabledNode 查找启用中的条目 // FindEnabledNode 查找启用中的条目
@@ -360,6 +362,8 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
// 分组 // 分组
if groupId > 0 { if groupId > 0 {
query.Attr("groupId", groupId) query.Attr("groupId", groupId)
} else if groupId < 0 {
query.Attr("groupId", 0)
} }
// 区域 // 区域
@@ -567,12 +571,12 @@ func (this *NodeDAO) FindEnabledNodeClusterIds(tx *dbs.Tx, nodeId int64) (result
result = append(result, clusterId) result = append(result, clusterId)
} }
for _, clusterId := range one.(*Node).DecodeSecondaryClusterIds() { for _, secondaryClusterId := range one.(*Node).DecodeSecondaryClusterIds() {
if lists.ContainsInt64(result, clusterId) { if lists.ContainsInt64(result, secondaryClusterId) {
continue continue
} }
result = append(result, clusterId) result = append(result, secondaryClusterId)
} }
return return
} }
@@ -661,16 +665,51 @@ func (this *NodeDAO) FindAllNodeIdsMatch(tx *dbs.Tx, clusterId int64, includeSec
} }
// FindAllEnabledNodesWithClusterId 获取一个集群的所有节点 // FindAllEnabledNodesWithClusterId 获取一个集群的所有节点
func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*Node, err error) { func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondary bool) (result []*Node, err error) {
_, err = this.Query(tx). var query = this.Query(tx)
if includeSecondary {
query.Where("(clusterId=:primaryClusterId OR JSON_CONTAINS(secondaryClusterIds, :primaryClusterIdString))").
Param("primaryClusterId", clusterId).
Param("primaryClusterIdString", types.String(clusterId))
} else {
query.Attr("clusterId", clusterId)
}
_, err = query.
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("clusterId", clusterId).
DescPk(). DescPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
} }
// FindEnabledAndOnNodeIdsWithClusterId 查找某个集群下的所有启用的节点IDs
func (this *NodeDAO) FindEnabledAndOnNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondary bool) ([]int64, error) {
var query = this.Query(tx)
if includeSecondary {
query.Where("(clusterId=:primaryClusterId OR JSON_CONTAINS(secondaryClusterIds, :primaryClusterIdString))").
Param("primaryClusterId", clusterId).
Param("primaryClusterIdString", types.String(clusterId))
} else {
query.Attr("clusterId", clusterId)
}
ones, err := query.
Attr("isOn", true).
State(NodeStateEnabled).
ResultPk().
FindAll()
if err != nil {
return nil, err
}
var result = []int64{}
for _, one := range ones {
result = append(result, int64(one.(*Node).Id))
}
return result, nil
}
// FindAllEnabledNodeIdsWithClusterId 获取一个集群的所有节点Ids // FindAllEnabledNodeIdsWithClusterId 获取一个集群的所有节点Ids
func (this *NodeDAO) FindAllEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64) (result []int64, err error) { func (this *NodeDAO) FindAllEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64) (result []int64, err error) {
ones, err := this.Query(tx). ones, err := this.Query(tx).
@@ -757,6 +796,8 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
// 分组 // 分组
if groupId > 0 { if groupId > 0 {
query.Attr("groupId", groupId) query.Attr("groupId", groupId)
} else if groupId < 0 {
query.Attr("groupId", 0)
} }
// 区域 // 区域
@@ -773,11 +814,20 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
} }
// UpdateNodeStatus 更改节点状态 // UpdateNodeStatus 更改节点状态
func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error { func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
_, err := this.Query(tx). if nodeStatus == nil {
return nil
}
nodeStatusJSON, err := json.Marshal(nodeStatus)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(nodeId). Pk(nodeId).
Set("isActive", true). Set("isActive", true).
Set("status", string(statusJSON)). Set("status", nodeStatusJSON).
Update() Update()
return err return err
} }
@@ -969,6 +1019,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
clusterIds = append(clusterIds, node.DecodeSecondaryClusterIds()...) clusterIds = append(clusterIds, node.DecodeSecondaryClusterIds()...)
var clusterIndex = 0 var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{} config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds { for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap) nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
if err != nil { if err != nil {
@@ -978,6 +1030,21 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
continue continue
} }
// 节点IP地址
nodeIPAddresses, err := SharedNodeIPAddressDAO.FindAllAccessibleIPAddressesWithClusterId(tx, nodeconfigs.NodeRoleNode, clusterId, cacheMap)
if err != nil {
return nil, err
}
for _, address := range nodeIPAddresses {
var ip = address.Ip
_, ok := allowIPMaps[ip]
if !ok {
allowIPMaps[ip] = true
config.AllowedIPs = append(config.AllowedIPs, ip)
}
}
// 防火墙
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId) var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
if httpFirewallPolicyId > 0 { if httpFirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap) firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap)
@@ -1012,7 +1079,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// 最大线程数、TCP连接数 // 最大线程数、TCP连接数
if clusterIndex == 0 { if clusterIndex == 0 {
config.MaxThreads = int(nodeCluster.NodeMaxThreads) config.MaxThreads = int(nodeCluster.NodeMaxThreads)
config.TCPMaxConnections = int(nodeCluster.NodeTCPMaxConnections) config.DDoSProtection = nodeCluster.DecodeDDoSProtection()
config.AutoOpenPorts = nodeCluster.AutoOpenPorts == 1 config.AutoOpenPorts = nodeCluster.AutoOpenPorts == 1
} }
@@ -1026,6 +1093,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
config.WebPImagePolicies[clusterId] = webpPolicy config.WebPImagePolicies[clusterId] = webpPolicy
} }
// UAM
if IsNotNull(nodeCluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(nodeCluster.Uam, uamPolicy)
if err != nil {
return nil, err
}
config.UAMPolicies[clusterId] = uamPolicy
}
clusterIndex++ clusterIndex++
} }
@@ -1070,6 +1147,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
config.SystemServices = services config.SystemServices = services
} }
// DNS Resolver
if IsNotNull(node.DnsResolver) {
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
err = json.Unmarshal(node.DnsResolver, dnsResolverConfig)
if err != nil {
return nil, err
}
config.DNSResolver = dnsResolverConfig
}
// 防火墙动作 // 防火墙动作
actions, err := SharedNodeClusterFirewallActionDAO.FindAllEnabledFirewallActions(tx, primaryClusterId, cacheMap) actions, err := SharedNodeClusterFirewallActionDAO.FindAllEnabledFirewallActions(tx, primaryClusterId, cacheMap)
if err != nil { if err != nil {
@@ -1134,6 +1221,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
} }
config.OCSPVersion = ocspVersion config.OCSPVersion = ocspVersion
// DDOS Protection
var ddosProtection = node.DecodeDDoSProtection()
if ddosProtection != nil {
if config.DDoSProtection == nil {
config.DDoSProtection = ddosProtection
} else {
config.DDoSProtection.Merge(ddosProtection)
}
}
// 初始化扩展配置 // 初始化扩展配置
err = this.composeExtConfig(tx, config, clusterIds, cacheMap) err = this.composeExtConfig(tx, config, clusterIds, cacheMap)
if err != nil { if err != nil {
@@ -1400,6 +1497,49 @@ func (this *NodeDAO) UpdateNodeDNS(tx *dbs.Tx, nodeId int64, routes map[int64][]
return nil return nil
} }
// FindNodeDNSResolver 查找域名DNS Resolver
func (this *NodeDAO) FindNodeDNSResolver(tx *dbs.Tx, nodeId int64) (*nodeconfigs.DNSResolverConfig, error) {
configJSON, err := this.Query(tx).
Pk(nodeId).
Result("dnsResolver").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(configJSON) {
return nodeconfigs.DefaultDNSResolverConfig(), nil
}
var config = nodeconfigs.DefaultDNSResolverConfig()
err = json.Unmarshal(configJSON, config)
if err != nil {
return nil, err
}
return config, nil
}
// UpdateNodeDNSResolver 修改域名DNS Resolver
func (this *NodeDAO) UpdateNodeDNSResolver(tx *dbs.Tx, nodeId int64, dnsResolverConfig *nodeconfigs.DNSResolverConfig) error {
if nodeId <= 0 {
return ErrNotFound
}
configJSON, err := json.Marshal(dnsResolverConfig)
if err != nil {
return err
}
var op = NewNodeOperator()
op.Id = nodeId
op.DnsResolver = configJSON
err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, nodeId)
}
// UpdateNodeSystem 设置系统信息 // UpdateNodeSystem 设置系统信息
func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) error { func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) error {
if nodeId <= 0 { if nodeId <= 0 {
@@ -1737,6 +1877,53 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
return return
} }
// FindNodeDDoSProtection 获取节点的DDOS设置
func (this *NodeDAO) FindNodeDDoSProtection(tx *dbs.Tx, nodeId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx).
Result("ddosProtection").
Pk(nodeId).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*Node).DecodeDDoSProtection(), nil
}
// UpdateNodeDDoSProtection 设置集群的DDOS设置
func (this *NodeDAO) UpdateNodeDDoSProtection(tx *dbs.Tx, nodeId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if nodeId <= 0 {
return ErrNotFound
}
var op = NewNodeOperator()
op.Id = nodeId
if ddosProtection == nil {
op.DdosProtection = "{}"
} else {
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return err
}
op.DdosProtection = ddosProtectionJSON
}
err := this.Save(tx, op)
if err != nil {
return err
}
clusterId, err := this.FindNodeClusterId(tx, nodeId)
if err != nil {
return err
}
if clusterId > 0 {
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, NodeTaskTypeDDosProtectionChanged, 0)
}
return nil
}
// NotifyUpdate 通知节点相关更新 // NotifyUpdate 通知节点相关更新
func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error { func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
// 这里只需要通知单个集群即可,因为节点是公用的,更新一个就相当于更新了所有 // 这里只需要通知单个集群即可,因为节点是公用的,更新一个就相当于更新了所有

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns" "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils" dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@@ -375,7 +376,15 @@ func (this *NodeIPAddressDAO) ListEnabledIPAddresses(tx *dbs.Tx, role string, no
} }
// FindAllAccessibleIPAddressesWithClusterId 列出所有的正在启用的IP地址 // FindAllAccessibleIPAddressesWithClusterId 列出所有的正在启用的IP地址
func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.Tx, role string, clusterId int64) (result []*NodeIPAddress, err error) { func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.Tx, role string, clusterId int64, cacheMap *utils.CacheMap) (result []*NodeIPAddress, err error) {
var cacheKey = this.Table + ":FindAllAccessibleIPAddressesWithClusterId:" + role + ":" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.([]*NodeIPAddress), nil
}
}
_, err = this.Query(tx). _, err = this.Query(tx).
State(NodeIPAddressStateEnabled). State(NodeIPAddressStateEnabled).
Attr("role", role). Attr("role", role).
@@ -385,6 +394,14 @@ func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.
Param("clusterId", clusterId). Param("clusterId", clusterId).
Slice(&result). Slice(&result).
FindAll() FindAll()
if err != nil {
return
}
if cacheMap != nil {
cacheMap.Put(cacheKey, result)
}
return return
} }

View File

@@ -360,3 +360,12 @@ func (this *NodeLogDAO) UpdateAllNodeLogsRead(tx *dbs.Tx) error {
Set("isRead", true). Set("isRead", true).
UpdateQuickly() UpdateQuickly()
} }
// DeleteNodeLogs 删除某个节点上的日志
func (this *NodeLogDAO) DeleteNodeLogs(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64) error {
_, err := this.Query(tx).
Attr("nodeId", nodeId).
Attr("role", role).
Delete()
return err
}

View File

@@ -31,10 +31,13 @@ type Node struct {
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点 ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
MaxCPU uint32 `field:"maxCPU"` // 可以使用的最多CPU MaxCPU uint32 `field:"maxCPU"` // 可以使用的最多CPU
MaxThreads uint32 `field:"maxThreads"` // 最大线程数
DdosProtection dbs.JSON `field:"ddosProtection"` // DDOS配置
DnsRoutes dbs.JSON `field:"dnsRoutes"` // DNS线路设置 DnsRoutes dbs.JSON `field:"dnsRoutes"` // DNS线路设置
MaxCacheDiskCapacity dbs.JSON `field:"maxCacheDiskCapacity"` // 硬盘缓存容量 MaxCacheDiskCapacity dbs.JSON `field:"maxCacheDiskCapacity"` // 硬盘缓存容量
MaxCacheMemoryCapacity dbs.JSON `field:"maxCacheMemoryCapacity"` // 内存缓存容量 MaxCacheMemoryCapacity dbs.JSON `field:"maxCacheMemoryCapacity"` // 内存缓存容量
CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录 CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
} }
type NodeOperator struct { type NodeOperator struct {
@@ -65,10 +68,13 @@ type NodeOperator struct {
State interface{} // 状态 State interface{} // 状态
ConnectedAPINodes interface{} // 当前连接的API节点 ConnectedAPINodes interface{} // 当前连接的API节点
MaxCPU interface{} // 可以使用的最多CPU MaxCPU interface{} // 可以使用的最多CPU
MaxThreads interface{} // 最大线程数
DdosProtection interface{} // DDOS配置
DnsRoutes interface{} // DNS线路设置 DnsRoutes interface{} // DNS线路设置
MaxCacheDiskCapacity interface{} // 硬盘缓存容量 MaxCacheDiskCapacity interface{} // 硬盘缓存容量
MaxCacheMemoryCapacity interface{} // 内存缓存容量 MaxCacheMemoryCapacity interface{} // 内存缓存容量
CacheDiskDir interface{} // 缓存目录 CacheDiskDir interface{} // 缓存目录
DnsResolver interface{} // DNS解析器
} }
func NewNodeOperator() *NodeOperator { func NewNodeOperator() *NodeOperator {

View File

@@ -3,6 +3,8 @@ package models
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"sort" "sort"
"time" "time"
) )
@@ -97,6 +99,7 @@ func (this *Node) DecodeSecondaryClusterIds() []int64 {
return result return result
} }
// AllClusterIds 获取所属集群IDs
func (this *Node) AllClusterIds() []int64 { func (this *Node) AllClusterIds() []int64 {
var result = []int64{} var result = []int64{}
@@ -108,3 +111,60 @@ func (this *Node) AllClusterIds() []int64 {
return result return result
} }
// DecodeDDoSProtection 解析DDoS Protection设置
func (this *Node) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
if IsNull(this.DdosProtection) {
return nil
}
var result = &ddosconfigs.ProtectionConfig{}
err := json.Unmarshal(this.DdosProtection, &result)
if err != nil {
// ignore err
}
return result
}
// HasDDoSProtection 检查是否有DDOS设置
func (this *Node) HasDDoSProtection() bool {
var config = this.DecodeDDoSProtection()
if config != nil {
return !config.IsPriorEmpty()
}
return false
}
func (this *Node) DecodeMaxCacheDiskCapacity() *shared.SizeCapacity {
if this.MaxCacheDiskCapacity.IsNull() {
return nil
}
// ignore error
capacity, _ := shared.DecodeSizeCapacityJSON(this.MaxCacheDiskCapacity)
return capacity
}
func (this *Node) DecodeMaxCacheMemoryCapacity() *shared.SizeCapacity {
if this.MaxCacheMemoryCapacity.IsNull() {
return nil
}
// ignore error
capacity, _ := shared.DecodeSizeCapacityJSON(this.MaxCacheMemoryCapacity)
return capacity
}
// DecodeDNSResolver 解析DNS解析主机配置
func (this *Node) DecodeDNSResolver() *nodeconfigs.DNSResolverConfig {
if this.DnsResolver.IsNull() {
return nil
}
var resolverConfig = nodeconfigs.DefaultDNSResolverConfig()
err := json.Unmarshal(this.DnsResolver, resolverConfig)
if err != nil {
// ignore error
}
return resolverConfig
}

View File

@@ -14,11 +14,12 @@ import (
type NodeTaskType = string type NodeTaskType = string
const ( const (
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged"
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged"
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged"
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged"
// NS相关 // NS相关

View File

@@ -52,16 +52,23 @@ func (this *NSNodeDAO) EnableNSNode(tx *dbs.Tx, id int64) error {
} }
// DisableNSNode 禁用条目 // DisableNSNode 禁用条目
func (this *NSNodeDAO) DisableNSNode(tx *dbs.Tx, id int64) error { func (this *NSNodeDAO) DisableNSNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", NSNodeStateDisabled). Set("state", NSNodeStateDisabled).
Update() Update()
if err != nil { if err != nil {
return err return err
} }
return this.NotifyUpdate(tx, id)
err = this.NotifyUpdate(tx, nodeId)
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleDNS, nodeId)
} }
// FindEnabledNSNode 查找启用中的条目 // FindEnabledNSNode 查找启用中的条目
@@ -339,13 +346,19 @@ func (this *NSNodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstall
} }
// UpdateNodeStatus 更改节点状态 // UpdateNodeStatus 更改节点状态
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error { func (this NSNodeDAO) 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

@@ -101,7 +101,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
maxIdleConns int32, maxIdleConns int32,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string) (originId int64, err error) { host string,
followPort bool) (originId int64, err error) {
var op = NewOriginOperator() var op = NewOriginOperator()
op.AdminId = adminId op.AdminId = adminId
op.UserId = userId op.UserId = userId
@@ -167,6 +168,7 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
} }
op.Host = host op.Host = host
op.FollowPort = followPort
op.State = OriginStateEnabled op.State = OriginStateEnabled
err = this.Save(tx, op) err = this.Save(tx, op)
@@ -191,7 +193,8 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
maxIdleConns int32, maxIdleConns int32,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string) error { host string,
followPort bool) error {
if originId <= 0 { if originId <= 0 {
return errors.New("invalid originId") return errors.New("invalid originId")
} }
@@ -262,6 +265,7 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
} }
op.Host = host op.Host = host
op.FollowPort = followPort
err := this.Save(tx, op) err := this.Save(tx, op)
if err != nil { if err != nil {
@@ -304,10 +308,11 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
RequestURI: origin.HttpRequestURI, RequestURI: origin.HttpRequestURI,
RequestHost: origin.Host, RequestHost: origin.Host,
Domains: origin.DecodeDomains(), Domains: origin.DecodeDomains(),
FollowPort: origin.FollowPort,
} }
if IsNotNull(origin.Addr) { if IsNotNull(origin.Addr) {
addr := &serverconfigs.NetworkAddressConfig{} var addr = &serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(origin.Addr, addr) err = json.Unmarshal(origin.Addr, addr)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -316,7 +321,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.ConnTimeout) { if IsNotNull(origin.ConnTimeout) {
connTimeout := &shared.TimeDuration{} var connTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.ConnTimeout, &connTimeout) err = json.Unmarshal(origin.ConnTimeout, &connTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -325,7 +330,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.ReadTimeout) { if IsNotNull(origin.ReadTimeout) {
readTimeout := &shared.TimeDuration{} var readTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.ReadTimeout, &readTimeout) err = json.Unmarshal(origin.ReadTimeout, &readTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -334,7 +339,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.IdleTimeout) { if IsNotNull(origin.IdleTimeout) {
idleTimeout := &shared.TimeDuration{} var idleTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.IdleTimeout, &idleTimeout) err = json.Unmarshal(origin.IdleTimeout, &idleTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -363,7 +368,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.HttpResponseHeader) { if IsNotNull(origin.HttpResponseHeader) {
ref := &shared.HTTPHeaderPolicyRef{} var ref = &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal(origin.HttpResponseHeader, ref) err = json.Unmarshal(origin.HttpResponseHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -382,7 +387,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.HealthCheck) { if IsNotNull(origin.HealthCheck) {
healthCheck := &serverconfigs.HealthCheckConfig{} var healthCheck = &serverconfigs.HealthCheckConfig{}
err = json.Unmarshal(origin.HealthCheck, healthCheck) err = json.Unmarshal(origin.HealthCheck, healthCheck)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -391,7 +396,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
if IsNotNull(origin.Cert) { if IsNotNull(origin.Cert) {
ref := &sslconfigs.SSLCertRef{} var ref = &sslconfigs.SSLCertRef{}
err = json.Unmarshal(origin.Cert, ref) err = json.Unmarshal(origin.Cert, ref)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -417,6 +422,19 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
return config, nil return config, nil
} }
// CheckUserOrigin 检查源站权限
func (this *OriginDAO) CheckUserOrigin(tx *dbs.Tx, userId int64, originId int64) error {
reverseProxyId, err := SharedReverseProxyDAO.FindReverseProxyContainsOriginId(tx, originId)
if err != nil {
return err
}
if reverseProxyId == 0 {
// 这里我们不允许源站没有被使用
return ErrNotFound
}
return SharedReverseProxyDAO.CheckUserReverseProxy(tx, userId, reverseProxyId)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *OriginDAO) NotifyUpdate(tx *dbs.Tx, originId int64) error { func (this *OriginDAO) NotifyUpdate(tx *dbs.Tx, originId int64) error {
reverseProxyId, err := SharedReverseProxyDAO.FindReverseProxyContainsOriginId(tx, originId) reverseProxyId, err := SharedReverseProxyDAO.FindReverseProxyContainsOriginId(tx, originId)

View File

@@ -29,6 +29,7 @@ type Origin struct {
Ftp dbs.JSON `field:"ftp"` // FTP相关设置 Ftp dbs.JSON `field:"ftp"` // FTP相关设置
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Domains dbs.JSON `field:"domains"` // 所属域名 Domains dbs.JSON `field:"domains"` // 所属域名
FollowPort bool `field:"followPort"` // 端口跟随
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
@@ -58,6 +59,7 @@ type OriginOperator struct {
Ftp interface{} // FTP相关设置 Ftp interface{} // FTP相关设置
CreatedAt interface{} // 创建时间 CreatedAt interface{} // 创建时间
Domains interface{} // 所属域名 Domains interface{} // 所属域名
FollowPort interface{} // 端口跟随
State interface{} // 状态 State interface{} // 状态
} }

View File

@@ -217,7 +217,7 @@ func (this *PlanDAO) ListEnabledPlans(tx *dbs.Tx, offset int64, size int64) (res
Limit(size). Limit(size).
Slice(&result). Slice(&result).
Desc("order"). Desc("order").
DescPk(). AscPk().
FindAll() FindAll()
return return
} }

View File

@@ -50,12 +50,17 @@ func (this *ReportNodeDAO) EnableReportNode(tx *dbs.Tx, id int64) error {
} }
// DisableReportNode 禁用条目 // DisableReportNode 禁用条目
func (this *ReportNodeDAO) DisableReportNode(tx *dbs.Tx, id int64) error { func (this *ReportNodeDAO) DisableReportNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", ReportNodeStateDisabled). Set("state", ReportNodeStateDisabled).
Update() Update()
return err if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleReport, nodeId)
} }
// FindEnabledReportNode 查找启用中的条目 // FindEnabledReportNode 查找启用中的条目
@@ -264,13 +269,19 @@ func (this *ReportNodeDAO) FindEnabledNodeIdWithUniqueId(tx *dbs.Tx, uniqueId st
} }
// UpdateNodeStatus 更改节点状态 // UpdateNodeStatus 更改节点状态
func (this ReportNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error { func (this ReportNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *reporterconfigs.Status) 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

@@ -99,17 +99,18 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, nil return nil, nil
} }
config := &serverconfigs.ReverseProxyConfig{} var config = &serverconfigs.ReverseProxyConfig{}
config.Id = int64(reverseProxy.Id) config.Id = int64(reverseProxy.Id)
config.IsOn = reverseProxy.IsOn config.IsOn = reverseProxy.IsOn
config.RequestHostType = types.Int8(reverseProxy.RequestHostType) config.RequestHostType = types.Int8(reverseProxy.RequestHostType)
config.RequestHost = reverseProxy.RequestHost config.RequestHost = reverseProxy.RequestHost
config.RequestHostExcludingPort = reverseProxy.RequestHostExcludingPort
config.RequestURI = reverseProxy.RequestURI config.RequestURI = reverseProxy.RequestURI
config.StripPrefix = reverseProxy.StripPrefix config.StripPrefix = reverseProxy.StripPrefix
config.AutoFlush = reverseProxy.AutoFlush == 1 config.AutoFlush = reverseProxy.AutoFlush == 1
config.FollowRedirects = reverseProxy.FollowRedirects == 1 config.FollowRedirects = reverseProxy.FollowRedirects == 1
schedulingConfig := &serverconfigs.SchedulingConfig{} var schedulingConfig = &serverconfigs.SchedulingConfig{}
if IsNotNull(reverseProxy.Scheduling) { if IsNotNull(reverseProxy.Scheduling) {
err = json.Unmarshal(reverseProxy.Scheduling, schedulingConfig) err = json.Unmarshal(reverseProxy.Scheduling, schedulingConfig)
if err != nil { if err != nil {
@@ -118,7 +119,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
config.Scheduling = schedulingConfig config.Scheduling = schedulingConfig
} }
if IsNotNull(reverseProxy.PrimaryOrigins) { if IsNotNull(reverseProxy.PrimaryOrigins) {
originRefs := []*serverconfigs.OriginRef{} var originRefs = []*serverconfigs.OriginRef{}
err = json.Unmarshal(reverseProxy.PrimaryOrigins, &originRefs) err = json.Unmarshal(reverseProxy.PrimaryOrigins, &originRefs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -135,13 +136,13 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
} }
if IsNotNull(reverseProxy.BackupOrigins) { if IsNotNull(reverseProxy.BackupOrigins) {
originRefs := []*serverconfigs.OriginRef{} var originRefs = []*serverconfigs.OriginRef{}
err = json.Unmarshal(reverseProxy.BackupOrigins, &originRefs) err = json.Unmarshal(reverseProxy.BackupOrigins, &originRefs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, originConfig := range originRefs { for _, ref := range originRefs {
originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, originConfig.OriginId, cacheMap) originConfig, err := SharedOriginDAO.ComposeOriginConfig(tx, ref.OriginId, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -153,7 +154,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
// add headers // add headers
if IsNotNull(reverseProxy.AddHeaders) { if IsNotNull(reverseProxy.AddHeaders) {
addHeaders := []string{} var addHeaders = []string{}
err = json.Unmarshal(reverseProxy.AddHeaders, &addHeaders) err = json.Unmarshal(reverseProxy.AddHeaders, &addHeaders)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -166,7 +167,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
config.MaxIdleConns = int(reverseProxy.MaxIdleConns) config.MaxIdleConns = int(reverseProxy.MaxIdleConns)
if IsNotNull(reverseProxy.ConnTimeout) { if IsNotNull(reverseProxy.ConnTimeout) {
connTimeout := &shared.TimeDuration{} var connTimeout = &shared.TimeDuration{}
err = json.Unmarshal(reverseProxy.ConnTimeout, &connTimeout) err = json.Unmarshal(reverseProxy.ConnTimeout, &connTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -175,7 +176,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
} }
if IsNotNull(reverseProxy.ReadTimeout) { if IsNotNull(reverseProxy.ReadTimeout) {
readTimeout := &shared.TimeDuration{} var readTimeout = &shared.TimeDuration{}
err = json.Unmarshal(reverseProxy.ReadTimeout, &readTimeout) err = json.Unmarshal(reverseProxy.ReadTimeout, &readTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -184,7 +185,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
} }
if IsNotNull(reverseProxy.IdleTimeout) { if IsNotNull(reverseProxy.IdleTimeout) {
idleTimeout := &shared.TimeDuration{} var idleTimeout = &shared.TimeDuration{}
err = json.Unmarshal(reverseProxy.IdleTimeout, &idleTimeout) err = json.Unmarshal(reverseProxy.IdleTimeout, &idleTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -304,6 +305,7 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
reverseProxyId int64, reverseProxyId int64,
requestHostType int8, requestHostType int8,
requestHost string, requestHost string,
requestHostExcludingPort bool,
requestURI string, requestURI string,
stripPrefix string, stripPrefix string,
autoFlush bool, autoFlush bool,
@@ -328,6 +330,7 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
op.RequestHostType = requestHostType op.RequestHostType = requestHostType
op.RequestHost = requestHost op.RequestHost = requestHost
op.RequestHostExcludingPort = requestHostExcludingPort
op.RequestURI = requestURI op.RequestURI = requestURI
op.StripPrefix = stripPrefix op.StripPrefix = stripPrefix
op.AutoFlush = autoFlush op.AutoFlush = autoFlush

View File

@@ -4,55 +4,57 @@ import "github.com/iwind/TeaGo/dbs"
// ReverseProxy 反向代理配置 // ReverseProxy 反向代理配置
type ReverseProxy struct { type ReverseProxy 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 bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Scheduling dbs.JSON `field:"scheduling"` // 调度算法 Scheduling dbs.JSON `field:"scheduling"` // 调度算法
PrimaryOrigins dbs.JSON `field:"primaryOrigins"` // 主要源站 PrimaryOrigins dbs.JSON `field:"primaryOrigins"` // 主要源站
BackupOrigins dbs.JSON `field:"backupOrigins"` // 备用源站 BackupOrigins dbs.JSON `field:"backupOrigins"` // 备用源站
StripPrefix string `field:"stripPrefix"` // 去除URL前缀 StripPrefix string `field:"stripPrefix"` // 去除URL前缀
RequestHostType uint8 `field:"requestHostType"` // 请求Host类型 RequestHostType uint8 `field:"requestHostType"` // 请求Host类型
RequestHost string `field:"requestHost"` // 请求Host RequestHost string `field:"requestHost"` // 请求Host
RequestURI string `field:"requestURI"` // 请求URI RequestHostExcludingPort bool `field:"requestHostExcludingPort"` // 移除请求Host中的域名
AutoFlush uint8 `field:"autoFlush"` // 是否自动刷新缓冲区 RequestURI string `field:"requestURI"` // 请求URI
AddHeaders dbs.JSON `field:"addHeaders"` // 自动添加的Header列表 AutoFlush uint8 `field:"autoFlush"` // 是否自动刷新缓冲区
State uint8 `field:"state"` // 状态 AddHeaders dbs.JSON `field:"addHeaders"` // 自动添加的Header列表
CreatedAt uint64 `field:"createdAt"` // 创建时间 State uint8 `field:"state"` // 状态
ConnTimeout dbs.JSON `field:"connTimeout"` // 连接超时时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
ReadTimeout dbs.JSON `field:"readTimeout"` // 读取超时时间 ConnTimeout dbs.JSON `field:"connTimeout"` // 连接超时时间
IdleTimeout dbs.JSON `field:"idleTimeout"` // 空闲超时时间 ReadTimeout dbs.JSON `field:"readTimeout"` // 读取超时时间
MaxConns uint32 `field:"maxConns"` // 最大并发连接数 IdleTimeout dbs.JSON `field:"idleTimeout"` // 空闲超时时间
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数 MaxConns uint32 `field:"maxConns"` // 最大并发连接数
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置 MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随 ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
} }
type ReverseProxyOperator struct { type ReverseProxyOperator struct {
Id interface{} // ID Id interface{} // ID
AdminId interface{} // 管理员ID AdminId interface{} // 管理员ID
UserId interface{} // 用户ID UserId interface{} // 用户ID
TemplateId interface{} // 模版ID TemplateId interface{} // 模版ID
IsOn interface{} // 是否启用 IsOn interface{} // 是否启用
Scheduling interface{} // 调度算法 Scheduling interface{} // 调度算法
PrimaryOrigins interface{} // 主要源站 PrimaryOrigins interface{} // 主要源站
BackupOrigins interface{} // 备用源站 BackupOrigins interface{} // 备用源站
StripPrefix interface{} // 去除URL前缀 StripPrefix interface{} // 去除URL前缀
RequestHostType interface{} // 请求Host类型 RequestHostType interface{} // 请求Host类型
RequestHost interface{} // 请求Host RequestHost interface{} // 请求Host
RequestURI interface{} // 请求URI RequestHostExcludingPort interface{} // 移除请求Host中的域名
AutoFlush interface{} // 是否自动刷新缓冲区 RequestURI interface{} // 请求URI
AddHeaders interface{} // 自动添加的Header列表 AutoFlush interface{} // 是否自动刷新缓冲区
State interface{} // 状态 AddHeaders interface{} // 自动添加的Header列表
CreatedAt interface{} // 创建时间 State interface{} // 状态
ConnTimeout interface{} // 连接超时时间 CreatedAt interface{} // 创建时间
ReadTimeout interface{} // 读取超时时间 ConnTimeout interface{} // 连接超时时间
IdleTimeout interface{} // 空闲超时时间 ReadTimeout interface{} // 读取超时时间
MaxConns interface{} // 最大并发连接数 IdleTimeout interface{} // 空闲超时时间
MaxIdleConns interface{} // 最大空闲连接数 MaxConns interface{} // 最大并发连接数
ProxyProtocol interface{} // Proxy Protocol配置 MaxIdleConns interface{} // 最大空闲连接数
FollowRedirects interface{} // 回源跟随 ProxyProtocol interface{} // Proxy Protocol配置
FollowRedirects interface{} // 回源跟随
} }
func NewReverseProxyOperator() *ReverseProxyOperator { func NewReverseProxyOperator() *ReverseProxyOperator {

View File

@@ -0,0 +1,215 @@
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/maps"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"math"
"sync"
"time"
)
type ServerBandwidthStatDAO dbs.DAO
const (
ServerBandwidthStatTablePartials = 20 // 分表数量
)
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 := SharedServerBandwidthStatDAO.Clean(nil)
if err != nil {
remotelogs.Error("SharedServerBandwidthStatDAO", "clean expired data failed: "+err.Error())
}
}
})
})
}
func NewServerBandwidthStatDAO() *ServerBandwidthStatDAO {
return dbs.NewDAO(&ServerBandwidthStatDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeServerBandwidthStats",
Model: new(ServerBandwidthStat),
PkName: "id",
},
}).(*ServerBandwidthStatDAO)
}
var SharedServerBandwidthStatDAO *ServerBandwidthStatDAO
func init() {
dbs.OnReady(func() {
SharedServerBandwidthStatDAO = NewServerBandwidthStatDAO()
})
}
// UpdateServerBandwidth 写入数据
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, day string, timeAt string, bytes int64) error {
if serverId <= 0 {
return errors.New("invalid server id '" + types.String(serverId) + "'")
}
return this.Query(tx).
Table(this.partialTable(serverId)).
Param("bytes", bytes).
InsertOrUpdateQuickly(maps.Map{
"userId": userId,
"serverId": serverId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
})
}
// FindMinutelyPeekBandwidthBytes 获取某分钟的带宽峰值
// day YYYYMMDD
// minute HHII
func (this *ServerBandwidthStatDAO) FindMinutelyPeekBandwidthBytes(tx *dbs.Tx, serverId int64, day string, minute string) (int64, error) {
return this.Query(tx).
Table(this.partialTable(serverId)).
Result("bytes").
Attr("serverId", serverId).
Attr("day", day).
Attr("timeAt", minute).
FindInt64Col(0)
}
// FindDailyPeekBandwidthBytes 获取某天的带宽峰值
// day YYYYMMDD
func (this *ServerBandwidthStatDAO) FindDailyPeekBandwidthBytes(tx *dbs.Tx, serverId int64, day string) (int64, error) {
return this.Query(tx).
Table(this.partialTable(serverId)).
Attr("day", day).
Result("MAX(bytes)").
FindInt64Col(0)
}
// FindMonthlyPeekBandwidthBytes 获取某月的带宽峰值
// month YYYYMM
func (this *ServerBandwidthStatDAO) FindMonthlyPeekBandwidthBytes(tx *dbs.Tx, serverId int64, month string) (int64, error) {
return this.Query(tx).
Table(this.partialTable(serverId)).
Between("day", month+"01", month+"31").
Result("MAX(bytes)").
FindInt64Col(0)
}
// FindServerStats 查找某个时间段的带宽统计
// 参数:
// - day YYYYMMDD
// - timeAt HHII
func (this *ServerBandwidthStatDAO) FindServerStats(tx *dbs.Tx, serverId int64, day string, timeFrom string, timeTo string) (result []*ServerBandwidthStat, err error) {
_, err = this.Query(tx).
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Attr("day", day).
Between("timeAt", timeFrom, timeTo).
Slice(&result).
FindAll()
return
}
// FindMonthlyPercentile 获取某月内百分位
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int) (result int64, err error) {
if percentile <= 0 {
percentile = 95
}
// 如果是100%以上,则快速返回
if percentile >= 100 {
result, err = this.Query(tx).
Table(this.partialTable(serverId)).
Result("bytes").
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
Desc("bytes").
Limit(1).
FindInt64Col(0)
return
}
// 总数量
total, err := this.Query(tx).
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
Count()
if err != nil {
return 0, err
}
if total == 0 {
return 0, nil
}
var offset int64
if total > 1 {
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
}
// 查询 nth 位置
result, err = this.Query(tx).
Table(this.partialTable(serverId)).
Result("bytes").
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
Desc("bytes").
Offset(offset).
Limit(1).
FindInt64Col(0)
return
}
// Clean 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -62)) // 保留大约2个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx).
Table(table).
Lt("day", day).
Delete()
return err
})
}
// 批量执行
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
var wg = sync.WaitGroup{}
wg.Add(ServerBandwidthStatTablePartials)
var resultErr error
for i := 0; i < ServerBandwidthStatTablePartials; i++ {
var table = this.partialTable(int64(i))
go func(table string) {
defer wg.Done()
err := f(table, locker)
if err != nil {
resultErr = err
}
}(table)
}
wg.Wait()
return resultErr
}
// 获取分区表
func (this *ServerBandwidthStatDAO) partialTable(serverId int64) string {
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartials))
}

View File

@@ -0,0 +1,55 @@
package models_test
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing"
"time"
)
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, 1, timeutil.Format("Ymd"), timeutil.Format("Hi"), 1024)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
var count = 1 // 测试时将此值设为一个比较大的数字
for i := 0; i < count; i++ {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200)))
var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
err := dao.UpdateServerBandwidth(tx, 1, 1, day, minute, 1024)
if err != nil {
t.Fatal(err)
}
}
t.Log("ok")
}
func TestServerBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95))
}
func TestServerBandwidthStatDAO_Clean(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
var before = time.Now()
err := dao.Clean(tx)
if err != nil {
t.Fatal(err)
}
t.Log("ok", time.Since(before).Seconds()*1000, "ms")
}

View File

@@ -0,0 +1,24 @@
package models
// ServerBandwidthStat 服务峰值带宽统计
type ServerBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节
}
type ServerBandwidthStatOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
ServerId interface{} // 服务ID
Day interface{} // 日期YYYYMMDD
TimeAt interface{} // 时间点HHMM
Bytes interface{} // 带宽字节
}
func NewServerBandwidthStatOperator() *ServerBandwidthStatOperator {
return &ServerBandwidthStatOperator{}
}

View File

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

View File

@@ -12,7 +12,6 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"math"
"regexp" "regexp"
"strings" "strings"
"time" "time"
@@ -405,45 +404,6 @@ func (this *ServerDailyStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, mont
FindInt64Col(0) FindInt64Col(0)
} }
// FindMonthlyPercentile 获取某月内百分位
func (this *ServerDailyStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int) (result int64, err error) {
if percentile <= 0 {
percentile = 95
}
if percentile > 100 {
percentile = 100
}
total, err := this.Query(tx).
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
Count()
if err != nil {
return 0, err
}
if total == 0 {
return 0, nil
}
var offset int64
if total > 1 {
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
}
result, err = this.Query(tx).
Result("bytes").
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
Desc("bytes").
Offset(offset).
Limit(1).
FindInt64Col(0)
// 因为是5分钟统计所以需要除以300
result = result / 300
return
}
// FindDailyStats 按天统计 // FindDailyStats 按天统计
func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) { func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) {
ones, err := this.Query(tx). ones, err := this.Query(tx).

View File

@@ -83,13 +83,3 @@ func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
} }
t.Log(serverIds) t.Log(serverIds)
} }
func TestServerDailyStatDAO_FindMonthlyPercentile(t *testing.T) {
var tx *dbs.Tx
var dao = NewServerDailyStatDAO()
result, err := dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95)
if err != nil {
t.Fatal(err)
}
t.Log("result:", result)
}

View File

@@ -156,8 +156,8 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
webId int64, webId int64,
reverseProxyJSON []byte, reverseProxyJSON []byte,
clusterId int64, clusterId int64,
includeNodesJSON string, includeNodesJSON []byte,
excludeNodesJSON string, excludeNodesJSON []byte,
groupIds []int64, groupIds []int64,
userPlanId int64) (serverId int64, err error) { userPlanId int64) (serverId int64, err error) {
var op = NewServerOperator() var op = NewServerOperator()
@@ -206,15 +206,15 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
op.Udp = udpJSON op.Udp = udpJSON
} }
op.WebId = webId op.WebId = webId
if len(reverseProxyJSON) > 0 { if IsNotNull(reverseProxyJSON) {
op.ReverseProxy = reverseProxyJSON op.ReverseProxy = reverseProxyJSON
} }
op.ClusterId = clusterId op.ClusterId = clusterId
if len(includeNodesJSON) > 0 { if IsNotNull(includeNodesJSON) {
op.IncludeNodes = includeNodesJSON op.IncludeNodes = includeNodesJSON
} }
if len(excludeNodesJSON) > 0 { if IsNotNull(excludeNodesJSON) {
op.ExcludeNodes = excludeNodesJSON op.ExcludeNodes = excludeNodesJSON
} }
@@ -338,12 +338,31 @@ func (this *ServerDAO) UpdateServerBasic(tx *dbs.Tx, serverId int64, name string
return nil return nil
} }
// UpdateServerGroupIds 修改服务所在分组
func (this *ServerDAO) UpdateServerGroupIds(tx *dbs.Tx, serverId int64, groupIds []int64) error {
if groupIds == nil {
groupIds = []int64{}
}
groupIdsJSON, err := json.Marshal(groupIds)
if err != nil {
return err
}
err = this.Query(tx).
Pk(serverId).
Set("groupIds", groupIdsJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, serverId)
}
// UpdateUserServerBasic 设置用户相关的基本信息 // UpdateUserServerBasic 设置用户相关的基本信息
func (this *ServerDAO) UpdateUserServerBasic(tx *dbs.Tx, serverId int64, name string) error { func (this *ServerDAO) UpdateUserServerBasic(tx *dbs.Tx, serverId int64, name string) error {
if serverId <= 0 { if serverId <= 0 {
return errors.New("serverId should not be smaller than 0") return errors.New("serverId should not be smaller than 0")
} }
op := NewServerOperator() var op = NewServerOperator()
op.Id = serverId op.Id = serverId
op.Name = name op.Name = name
@@ -752,8 +771,9 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
} }
if len(keyword) > 0 { if len(keyword) > 0 {
if regexp.MustCompile(`^\d+$`).MatchString(keyword) { if regexp.MustCompile(`^\d+$`).MatchString(keyword) {
query.Where("(name LIKE :keyword OR serverNames LIKE :keyword OR JSON_CONTAINS(http, :portRange, '$.listen') OR JSON_CONTAINS(https, :portRange, '$.listen') OR JSON_CONTAINS(tcp, :portRange, '$.listen') OR JSON_CONTAINS(tls, :portRange, '$.listen'))"). query.Where("(id=:serverId OR name LIKE :keyword OR serverNames LIKE :keyword OR JSON_CONTAINS(http, :portRange, '$.listen') OR JSON_CONTAINS(https, :portRange, '$.listen') OR JSON_CONTAINS(tcp, :portRange, '$.listen') OR JSON_CONTAINS(tls, :portRange, '$.listen'))").
Param("portRange", maps.Map{"portRange": keyword}.AsJSON()). Param("portRange", maps.Map{"portRange": keyword}.AsJSON()).
Param("serverId", keyword).
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} else { } else {
query.Where("(name LIKE :keyword OR serverNames LIKE :keyword)"). query.Where("(name LIKE :keyword OR serverNames LIKE :keyword)").
@@ -806,8 +826,9 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
} }
if len(keyword) > 0 { if len(keyword) > 0 {
if regexp.MustCompile(`^\d+$`).MatchString(keyword) { if regexp.MustCompile(`^\d+$`).MatchString(keyword) {
query.Where("(name LIKE :keyword OR serverNames LIKE :keyword OR JSON_CONTAINS(http, :portRange, '$.listen') OR JSON_CONTAINS(https, :portRange, '$.listen') OR JSON_CONTAINS(tcp, :portRange, '$.listen') OR JSON_CONTAINS(tls, :portRange, '$.listen'))"). query.Where("(id=:serverId OR name LIKE :keyword OR serverNames LIKE :keyword OR JSON_CONTAINS(http, :portRange, '$.listen') OR JSON_CONTAINS(https, :portRange, '$.listen') OR JSON_CONTAINS(tcp, :portRange, '$.listen') OR JSON_CONTAINS(tls, :portRange, '$.listen'))").
Param("portRange", string(maps.Map{"portRange": keyword}.AsJSON())). Param("portRange", string(maps.Map{"portRange": keyword}.AsJSON())).
Param("serverId", keyword).
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} else { } else {
query.Where("(name LIKE :keyword OR serverNames LIKE :keyword)"). query.Where("(name LIKE :keyword OR serverNames LIKE :keyword)").
@@ -1020,9 +1041,10 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
return cache.(*serverconfigs.ServerConfig), nil return cache.(*serverconfigs.ServerConfig), nil
} }
config := &serverconfigs.ServerConfig{} var config = &serverconfigs.ServerConfig{}
config.Id = int64(server.Id) config.Id = int64(server.Id)
config.ClusterId = int64(server.ClusterId) config.ClusterId = int64(server.ClusterId)
config.UserId = int64(server.UserId)
config.Type = server.Type config.Type = server.Type
config.IsOn = server.IsOn config.IsOn = server.IsOn
config.Name = server.Name config.Name = server.Name
@@ -1044,7 +1066,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// ServerNames // ServerNames
if IsNotNull(server.ServerNames) { if IsNotNull(server.ServerNames) {
serverNames := []*serverconfigs.ServerNameConfig{} var serverNames = []*serverconfigs.ServerNameConfig{}
err := json.Unmarshal(server.ServerNames, &serverNames) err := json.Unmarshal(server.ServerNames, &serverNames)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1060,20 +1082,29 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
return nil, err return nil, err
} }
if clusterDNS != nil && clusterDNS.DnsDomainId > 0 { if clusterDNS != nil && clusterDNS.DnsDomainId > 0 {
clusterDNSConfig, err := clusterDNS.DecodeDNSConfig()
if err != nil {
return nil, err
}
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, int64(clusterDNS.DnsDomainId), cacheMap) domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, int64(clusterDNS.DnsDomainId), cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if domain != nil { if domain != nil {
cname := server.DnsName + "." + domain.Name var cname = server.DnsName + "." + domain.Name
config.AliasServerNames = append(config.AliasServerNames, cname) config.CNameDomain = cname
if clusterDNSConfig.CNameAsDomain {
config.CNameAsDomain = true
config.AliasServerNames = append(config.AliasServerNames, cname)
}
} }
} }
} }
// HTTP // HTTP
if IsNotNull(server.Http) { if IsNotNull(server.Http) {
httpConfig := &serverconfigs.HTTPProtocolConfig{} var httpConfig = &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal(server.Http, httpConfig) err := json.Unmarshal(server.Http, httpConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1083,7 +1114,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// HTTPS // HTTPS
if IsNotNull(server.Https) { if IsNotNull(server.Https) {
httpsConfig := &serverconfigs.HTTPSProtocolConfig{} var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(server.Https, httpsConfig) err := json.Unmarshal(server.Https, httpsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1105,7 +1136,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// TCP // TCP
if IsNotNull(server.Tcp) { if IsNotNull(server.Tcp) {
tcpConfig := &serverconfigs.TCPProtocolConfig{} var tcpConfig = &serverconfigs.TCPProtocolConfig{}
err := json.Unmarshal(server.Tcp, tcpConfig) err := json.Unmarshal(server.Tcp, tcpConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1115,7 +1146,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// TLS // TLS
if IsNotNull(server.Tls) { if IsNotNull(server.Tls) {
tlsConfig := &serverconfigs.TLSProtocolConfig{} var tlsConfig = &serverconfigs.TLSProtocolConfig{}
err := json.Unmarshal(server.Tls, tlsConfig) err := json.Unmarshal(server.Tls, tlsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1137,7 +1168,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// Unix // Unix
if IsNotNull(server.Unix) { if IsNotNull(server.Unix) {
unixConfig := &serverconfigs.UnixProtocolConfig{} var unixConfig = &serverconfigs.UnixProtocolConfig{}
err := json.Unmarshal(server.Unix, unixConfig) err := json.Unmarshal(server.Unix, unixConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1147,7 +1178,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// UDP // UDP
if IsNotNull(server.Udp) { if IsNotNull(server.Udp) {
udpConfig := &serverconfigs.UDPProtocolConfig{} var udpConfig = &serverconfigs.UDPProtocolConfig{}
err := json.Unmarshal(server.Udp, udpConfig) err := json.Unmarshal(server.Udp, udpConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1168,7 +1199,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// ReverseProxy // ReverseProxy
if IsNotNull(server.ReverseProxy) { if IsNotNull(server.ReverseProxy) {
reverseProxyRef := &serverconfigs.ReverseProxyRef{} var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
err := json.Unmarshal(server.ReverseProxy, reverseProxyRef) err := json.Unmarshal(server.ReverseProxy, reverseProxyRef)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1185,7 +1216,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
} }
// WAF策略 // WAF策略
clusterId := int64(server.ClusterId) var clusterId = int64(server.ClusterId)
httpFirewallPolicyId, err := SharedNodeClusterDAO.FindClusterHTTPFirewallPolicyId(tx, clusterId, cacheMap) httpFirewallPolicyId, err := SharedNodeClusterDAO.FindClusterHTTPFirewallPolicyId(tx, clusterId, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1476,6 +1507,7 @@ func (this *ServerDAO) FindAllServersDNSWithClusterId(tx *dbs.Tx, clusterId int6
} }
// FindAllEnabledServersWithDomain 根据域名查找服务 // FindAllEnabledServersWithDomain 根据域名查找服务
// TODO 需要改成使用plainServerNames
func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string) (result []*Server, err error) { func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string) (result []*Server, err error) {
if len(domain) == 0 { if len(domain) == 0 {
return return
@@ -1523,6 +1555,49 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
return return
} }
// FindEnabledServerWithDomain 根据域名查找服务集群ID
func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (server *Server, err error) {
if len(domain) == 0 {
return
}
one, err := this.Query(tx).
State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(domain)).
Result("id", "userId", "clusterId").
AscPk().
Find()
if err != nil {
return nil, err
}
if one != nil {
return one.(*Server), nil
}
// 尝试泛解析
var dotIndex = strings.Index(domain, ".")
if dotIndex > 0 {
var wildcardDomain = "*." + domain[dotIndex+1:]
one, err = this.Query(tx).
State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(wildcardDomain)).
Result("id", "userId", "clusterId").
AscPk().
Find()
if err != nil {
return nil, err
}
if one != nil {
return one.(*Server), nil
}
}
return
}
// GenerateServerDNSName 重新生成子域名 // GenerateServerDNSName 重新生成子域名
func (this *ServerDAO) GenerateServerDNSName(tx *dbs.Tx, serverId int64) (string, error) { func (this *ServerDAO) GenerateServerDNSName(tx *dbs.Tx, serverId int64) (string, error) {
if serverId <= 0 { if serverId <= 0 {
@@ -1650,6 +1725,7 @@ func (this *ServerDAO) CheckUserServer(tx *dbs.Tx, userId int64, serverId int64)
func (this *ServerDAO) UpdateUserServersClusterId(tx *dbs.Tx, userId int64, oldClusterId, newClusterId int64) error { func (this *ServerDAO) UpdateUserServersClusterId(tx *dbs.Tx, userId int64, oldClusterId, newClusterId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Attr("userId", userId). Attr("userId", userId).
Attr("userPlanId", 0).
Set("clusterId", newClusterId). Set("clusterId", newClusterId).
Update() Update()
if err != nil { if err != nil {

View File

@@ -3,6 +3,7 @@ package models_test
import ( import (
"crypto/md5" "crypto/md5"
"encoding/json" "encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
@@ -10,10 +11,36 @@ import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"testing" "testing"
"time" "time"
) )
func TestServerDAO_CreateManyServers(t *testing.T) {
dbs.NotifyReady()
var dao = models.NewServerDAO()
var tx *dbs.Tx
var count = 10000
for i := 0; i < count; i++ {
var serverNames = []*serverconfigs.ServerNameConfig{
{
Name: "s" + types.String(i) + ".teaos.cn",
},
}
serverNamesJSON, err := json.Marshal(serverNames)
if err != nil {
t.Fatal(err)
}
serverId, err := dao.CreateServer(tx, 0, 0, serverconfigs.ServerTypeHTTPProxy, "TEST"+types.String(i), "", serverNamesJSON, false, nil, nil, nil, nil, nil, nil, nil, 0, nil, 1, nil, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
_ = serverId
}
}
func TestServerDAO_ComposeServerConfig(t *testing.T) { func TestServerDAO_ComposeServerConfig(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
@@ -195,6 +222,25 @@ func TestServerDAO_FindAllEnabledServersWithDomain(t *testing.T) {
} }
} }
func TestServerDAO_FindEnabledServerWithDomain(t *testing.T) {
var dao = models.NewServerDAO()
var tx *dbs.Tx
for _, domain := range []string{"a", "a.com", "teaos.cn", "www.teaos.cn", "cdn.teaos.cn", "google.com"} {
var before = time.Now()
server, err := dao.FindEnabledServerWithDomain(tx, domain)
var costMs = time.Since(before).Seconds() * 1000
if err != nil {
t.Fatal(err)
}
if server == nil {
t.Log(domain, "NULL", fmt.Sprintf("%.2fms", costMs))
} else {
t.Log(domain, string(maps.Map{"id": server.Id, "clusterId": server.ClusterId, "userId": server.UserId}.AsJSON()), fmt.Sprintf("%.2fms", costMs))
}
}
}
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) { func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()

View File

@@ -410,6 +410,17 @@ func (this *ServerGroupDAO) CheckUserGroup(tx *dbs.Tx, userId int64, groupId int
return nil return nil
} }
// ExistsGroup 检查分组ID是否存在
func (this *ServerGroupDAO) ExistsGroup(tx *dbs.Tx, groupId int64) (bool, error) {
if groupId <= 0 {
return false, nil
}
return this.Query(tx).
Pk(groupId).
State(ServerGroupStateEnabled).
Exist()
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error { func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId) serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId)

View File

@@ -0,0 +1,143 @@
package models
import (
"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/maps"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"sync"
"time"
)
type UserBandwidthStatDAO dbs.DAO
const (
UserBandwidthStatTablePartials = 20
)
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 := SharedUserBandwidthStatDAO.Clean(nil)
if err != nil {
remotelogs.Error("SharedUserBandwidthStatDAO", "clean expired data failed: "+err.Error())
}
}
})
})
}
func NewUserBandwidthStatDAO() *UserBandwidthStatDAO {
return dbs.NewDAO(&UserBandwidthStatDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserBandwidthStats",
Model: new(UserBandwidthStat),
PkName: "id",
},
}).(*UserBandwidthStatDAO)
}
var SharedUserBandwidthStatDAO *UserBandwidthStatDAO
func init() {
dbs.OnReady(func() {
SharedUserBandwidthStatDAO = NewUserBandwidthStatDAO()
})
}
// UpdateUserBandwidth 写入数据
func (this *UserBandwidthStatDAO) UpdateUserBandwidth(tx *dbs.Tx, userId int64, day string, timeAt string, bytes int64) error {
if userId <= 0 {
// 如果用户ID不大于0则说明服务不属于任何用户此时不需要处理
return nil
}
return this.Query(tx).
Table(this.partialTable(userId)).
Param("bytes", bytes).
InsertOrUpdateQuickly(maps.Map{
"userId": userId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
})
}
// FindUserPeekBandwidthInMonth 读取某月带宽峰值
// month YYYYMM
func (this *UserBandwidthStatDAO) FindUserPeekBandwidthInMonth(tx *dbs.Tx, userId int64, month string) (*UserBandwidthStat, error) {
one, err := this.Query(tx).
Table(this.partialTable(userId)).
Attr("userId", userId).
Between("day", month+"01", month+"31").
Desc("bytes").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*UserBandwidthStat), nil
}
// FindUserPeekBandwidthInDay 读取某日带宽峰值
// day YYYYMMDD
func (this *UserBandwidthStatDAO) FindUserPeekBandwidthInDay(tx *dbs.Tx, userId int64, day string) (*UserBandwidthStat, error) {
one, err := this.Query(tx).
Table(this.partialTable(userId)).
Attr("userId", userId).
Attr("day", day).
Desc("bytes").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*UserBandwidthStat), nil
}
// Clean 清理过期数据
func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -62)) // 保留大约2个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx).
Table(table).
Lt("day", day).
Delete()
return err
})
}
// 批量执行
func (this *UserBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
var wg = sync.WaitGroup{}
wg.Add(UserBandwidthStatTablePartials)
var resultErr error
for i := 0; i < UserBandwidthStatTablePartials; i++ {
var table = this.partialTable(int64(i))
go func(table string) {
defer wg.Done()
err := f(table, locker)
if err != nil {
resultErr = err
}
}(table)
}
wg.Wait()
return resultErr
}
// 获取分区表
func (this *UserBandwidthStatDAO) partialTable(userId int64) string {
return this.Table + "_" + types.String(userId%int64(UserBandwidthStatTablePartials))
}

View File

@@ -0,0 +1,30 @@
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 TestUserBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewUserBandwidthStatDAO()
var tx *dbs.Tx
err := dao.UpdateUserBandwidth(tx, 1, timeutil.Format("Ymd"), timeutil.Format("Hi"), 1024)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestUserBandwidthStatDAO_Clean(t *testing.T) {
var dao = models.NewUserBandwidthStatDAO()
var tx *dbs.Tx
err := dao.Clean(tx)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -0,0 +1,22 @@
package models
// UserBandwidthStat 用户月带宽峰值
type UserBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHII
Bytes uint64 `field:"bytes"` // 带宽
}
type UserBandwidthStatOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
Day interface{} // 日期YYYYMMDD
TimeAt interface{} // 时间点HHII
Bytes interface{} // 带宽
}
func NewUserBandwidthStatOperator() *UserBandwidthStatOperator {
return &UserBandwidthStatOperator{}
}

View File

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

View File

@@ -236,7 +236,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位 // 百分位
var percentile = 95 var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }
@@ -257,7 +257,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
percentile = 100 percentile = 100
} }
} }
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }
@@ -306,7 +306,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位 // 百分位
var percentile = 95 var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }
@@ -343,7 +343,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位 // 百分位
var percentile = 95 var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }
@@ -361,7 +361,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位 // 百分位
var percentile = 95 var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }
@@ -382,7 +382,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
percentile = 100 percentile = 100
} }
} }
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile) percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -169,7 +169,7 @@ func (this *UserDAO) UpdateUser(tx *dbs.Tx, userId int64, username string, passw
if userId <= 0 { if userId <= 0 {
return errors.New("invalid userId") return errors.New("invalid userId")
} }
op := NewUserOperator() var op = NewUserOperator()
op.Id = userId op.Id = userId
op.Username = username op.Username = username
if len(password) > 0 { if len(password) > 0 {

View File

@@ -0,0 +1,184 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"time"
)
const (
UserIdentityStateEnabled = 1 // 已启用
UserIdentityStateDisabled = 0 // 已禁用
)
type UserIdentityDAO dbs.DAO
func NewUserIdentityDAO() *UserIdentityDAO {
return dbs.NewDAO(&UserIdentityDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUserIdentities",
Model: new(UserIdentity),
PkName: "id",
},
}).(*UserIdentityDAO)
}
var SharedUserIdentityDAO *UserIdentityDAO
func init() {
dbs.OnReady(func() {
SharedUserIdentityDAO = NewUserIdentityDAO()
})
}
// EnableUserIdentity 启用条目
func (this *UserIdentityDAO) EnableUserIdentity(tx *dbs.Tx, id uint64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", UserIdentityStateEnabled).
Update()
return err
}
// DisableUserIdentity 禁用条目
func (this *UserIdentityDAO) DisableUserIdentity(tx *dbs.Tx, id uint64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", UserIdentityStateDisabled).
Update()
return err
}
// FindEnabledUserIdentity 查找启用中的条目
func (this *UserIdentityDAO) FindEnabledUserIdentity(tx *dbs.Tx, id int64) (*UserIdentity, error) {
result, err := this.Query(tx).
Pk(id).
Attr("state", UserIdentityStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*UserIdentity), err
}
// CreateUserIdentity 创建
func (this *UserIdentityDAO) CreateUserIdentity(tx *dbs.Tx, userId int64, idType userconfigs.UserIdentityType, realName string, number string, fileIds []int64) (int64, error) {
var op = NewUserIdentityOperator()
op.UserId = userId
op.Type = idType
op.RealName = realName
op.Number = number
if fileIds == nil {
fileIds = []int64{}
}
fileIdsJSON, err := json.Marshal(fileIds)
if err != nil {
return 0, err
}
op.FileIds = fileIdsJSON
op.Status = userconfigs.UserIdentityStatusNone
op.State = UserIdentityStateEnabled
return this.SaveInt64(tx, op)
}
// UpdateUserIdentity 修改
func (this *UserIdentityDAO) UpdateUserIdentity(tx *dbs.Tx, identityId int64, idType userconfigs.UserIdentityType, realName string, number string, fileIds []int64) error {
if identityId <= 0 {
return nil
}
var op = NewUserIdentityOperator()
op.Id = identityId
op.Type = idType
op.Number = number
if fileIds == nil {
fileIds = []int64{}
}
fileIdsJSON, err := json.Marshal(fileIds)
if err != nil {
return err
}
op.FileIds = fileIdsJSON
return this.Save(tx, op)
}
// SubmitUserIdentity 提交审核
func (this *UserIdentityDAO) SubmitUserIdentity(tx *dbs.Tx, identityId int64) error {
return this.Query(tx).
Pk(identityId).
Set("status", userconfigs.UserIdentityStatusSubmitted).
Set("submittedAt", time.Now().Unix()).
UpdateQuickly()
}
// CancelUserIdentity 取消提交审核
func (this *UserIdentityDAO) CancelUserIdentity(tx *dbs.Tx, identityId int64) error {
return this.Query(tx).
Pk(identityId).
Set("status", userconfigs.UserIdentityStatusNone).
Set("updatedAt", time.Now().Unix()).
UpdateQuickly()
}
// RejectUserIdentity 拒绝
func (this *UserIdentityDAO) RejectUserIdentity(tx *dbs.Tx, identityId int64) error {
return this.Query(tx).
Pk(identityId).
Set("status", userconfigs.UserIdentityStatusRejected).
Set("rejectedAt", time.Now().Unix()).
UpdateQuickly()
}
// VerifyUserIdentity 通过
func (this *UserIdentityDAO) VerifyUserIdentity(tx *dbs.Tx, identityId int64) error {
return this.Query(tx).
Pk(identityId).
Set("status", userconfigs.UserIdentityStatusVerified).
Set("verifiedAt", time.Now().Unix()).
UpdateQuickly()
}
// CheckUserIdentity 检查用户认证
func (this *UserIdentityDAO) CheckUserIdentity(tx *dbs.Tx, userId int64, identityId int64) error {
b, err := this.Query(tx).
Pk(identityId).
Attr("userId", userId).
State(UserIdentityStateEnabled).
Exist()
if err != nil {
return err
}
if !b {
return ErrNotFound
}
return nil
}
// FindUserIdentityStatus 查找认证信息当前状态
func (this *UserIdentityDAO) FindUserIdentityStatus(tx *dbs.Tx, identityId int64) (userconfigs.UserIdentityStatus, error) {
return this.Query(tx).
Pk(identityId).
Result("status").
FindStringCol("")
}
// FindEnabledUserIdentityWithType 查找某个类型的认证信息
func (this *UserIdentityDAO) FindEnabledUserIdentityWithType(tx *dbs.Tx, userId int64, idType userconfigs.UserIdentityType) (*UserIdentity, error) {
one, err := this.Query(tx).
Attr("userId", userId).
Attr("type", idType).
State(UserIdentityStateEnabled).
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*UserIdentity), nil
}

View File

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

View File

@@ -0,0 +1,40 @@
package models
import "github.com/iwind/TeaGo/dbs"
// UserIdentity 用户实名认证信息
type UserIdentity struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
Type string `field:"type"` // 类型
RealName string `field:"realName"` // 真实姓名
Number string `field:"number"` // 编号
FileIds dbs.JSON `field:"fileIds"` // 文件ID
Status string `field:"status"` // 状态none,submitted,verified,rejected
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
SubmittedAt uint64 `field:"submittedAt"` // 提交时间
RejectedAt uint64 `field:"rejectedAt"` // 拒绝时间
VerifiedAt uint64 `field:"verifiedAt"` // 认证时间
}
type UserIdentityOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
Type interface{} // 类型
RealName interface{} // 真实姓名
Number interface{} // 编号
FileIds interface{} // 文件ID
Status interface{} // 状态none,submitted,verified,rejected
State interface{} // 状态
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
SubmittedAt interface{} // 提交时间
RejectedAt interface{} // 拒绝时间
VerifiedAt interface{} // 认证时间
}
func NewUserIdentityOperator() *UserIdentityOperator {
return &UserIdentityOperator{}
}

View File

@@ -0,0 +1,16 @@
package models
import "encoding/json"
func (this *UserIdentity) DecodeFileIds() []int64 {
if len(this.FileIds) == 0 {
return []int64{}
}
var result = []int64{}
err := json.Unmarshal(this.FileIds, &result)
if err != nil {
// ignore error
}
return result
}

View File

@@ -51,12 +51,17 @@ func (this *UserNodeDAO) EnableUserNode(tx *dbs.Tx, id uint32) error {
} }
// DisableUserNode 禁用条目 // DisableUserNode 禁用条目
func (this *UserNodeDAO) DisableUserNode(tx *dbs.Tx, id int64) error { func (this *UserNodeDAO) DisableUserNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(nodeId).
Set("state", UserNodeStateDisabled). Set("state", UserNodeStateDisabled).
Update() Update()
return err if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleUser, nodeId)
} }
// FindEnabledUserNode 查找启用中的条目 // FindEnabledUserNode 查找启用中的条目
@@ -254,13 +259,19 @@ func (this *UserNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
} }
// UpdateNodeStatus 更改节点状态 // UpdateNodeStatus 更改节点状态
func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error { func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if len(statusJSON) == 0 { 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

@@ -17,18 +17,26 @@ type AliDNSProvider struct {
accessKeyId string accessKeyId string
accessKeySecret string accessKeySecret string
regionId string
} }
// Auth 认证 // Auth 认证
func (this *AliDNSProvider) Auth(params maps.Map) error { func (this *AliDNSProvider) Auth(params maps.Map) error {
this.accessKeyId = params.GetString("accessKeyId") this.accessKeyId = params.GetString("accessKeyId")
this.accessKeySecret = params.GetString("accessKeySecret") this.accessKeySecret = params.GetString("accessKeySecret")
this.regionId = params.GetString("regionId")
if len(this.accessKeyId) == 0 { if len(this.accessKeyId) == 0 {
return errors.New("'accessKeyId' should not be empty") return errors.New("'accessKeyId' should not be empty")
} }
if len(this.accessKeySecret) == 0 { if len(this.accessKeySecret) == 0 {
return errors.New("'accessKeySecret' should not be empty") return errors.New("'accessKeySecret' should not be empty")
} }
if len(this.regionId) == 0 {
this.regionId = "cn-hangzhou"
}
return nil return nil
} }
@@ -196,7 +204,7 @@ func (this *AliDNSProvider) DefaultRoute() string {
func (this *AliDNSProvider) doAPI(req requests.AcsRequest, resp responses.AcsResponse) error { func (this *AliDNSProvider) doAPI(req requests.AcsRequest, resp responses.AcsResponse) error {
req.SetScheme("https") req.SetScheme("https")
client, err := alidns.NewClientWithAccessKey("cn-hangzhou", this.accessKeyId, this.accessKeySecret) client, err := alidns.NewClientWithAccessKey(this.regionId, this.accessKeyId, this.accessKeySecret)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -71,7 +71,7 @@ func TestAliDNSProvider_AddRecord(t *testing.T) {
Name: "test", Name: "test",
Type: dnstypes.RecordTypeA, Type: dnstypes.RecordTypeA,
Value: "192.168.1.100", Value: "192.168.1.100",
Route: "unicom", Route: "aliyun_r_cn-beijing",
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -103,7 +103,7 @@ func testAliDNSProvider() (ProviderInterface, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='alidns' ORDER BY id DESC") one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='alidns' AND state=1 ORDER BY id DESC")
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -11,7 +11,6 @@ const (
ProviderTypeDNSPod ProviderType = "dnspod" // DNSPod ProviderTypeDNSPod ProviderType = "dnspod" // DNSPod
ProviderTypeAliDNS ProviderType = "alidns" // 阿里云DNS ProviderTypeAliDNS ProviderType = "alidns" // 阿里云DNS
ProviderTypeHuaweiDNS ProviderType = "huaweiDNS" // 华为DNS ProviderTypeHuaweiDNS ProviderType = "huaweiDNS" // 华为DNS
ProviderTypeDNSCom ProviderType = "dnscom" // dns.com
ProviderTypeCloudFlare ProviderType = "cloudFlare" // CloudFlare DNS ProviderTypeCloudFlare ProviderType = "cloudFlare" // CloudFlare DNS
ProviderTypeLocalEdgeDNS ProviderType = "localEdgeDNS" // 和当前系统集成的EdgeDNS ProviderTypeLocalEdgeDNS ProviderType = "localEdgeDNS" // 和当前系统集成的EdgeDNS
ProviderTypeUserEdgeDNS ProviderType = "userEdgeDNS" // 通过API连接的EdgeDNS ProviderTypeUserEdgeDNS ProviderType = "userEdgeDNS" // 通过API连接的EdgeDNS
@@ -36,11 +35,6 @@ func FindAllProviderTypes() []maps.Map {
"code": ProviderTypeHuaweiDNS, "code": ProviderTypeHuaweiDNS,
"description": "华为云解析DNS。", "description": "华为云解析DNS。",
}, },
/**{
"name": "帝恩思DNS.COM",
"code": ProviderTypeDNSCom,
"description": "DNS.com提供的DNS服务。",
},**/
{ {
"name": "CloudFlare DNS", "name": "CloudFlare DNS",
"code": ProviderTypeCloudFlare, "code": ProviderTypeCloudFlare,

View File

@@ -0,0 +1,90 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package installers
import (
"github.com/TeaOSLab/EdgeAPI/internal/utils/sizes"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/types"
"sync"
"time"
)
const (
UpgradeLimiterDuration = 10 // node key expire time, by seconds
UpgradeLimiterConcurrent = 10 // 10 nodes
UpgradeLimiterMaxBytesPerSecond = 5 * sizes.M // max bytes per second
)
var SharedUpgradeLimiter = NewUpgradeLimiter()
// UpgradeLimiter 升级流量管理器
type UpgradeLimiter struct {
nodeMap map[string]int64 // key => timestamp
rateTimestamp int64
rateBytes int64
locker sync.Mutex
}
func NewUpgradeLimiter() *UpgradeLimiter {
return &UpgradeLimiter{
nodeMap: map[string]int64{},
}
}
// UpdateNodeBytes 添加正在下载的节点流量
func (this *UpgradeLimiter) UpdateNodeBytes(nodeType nodeconfigs.NodeRole, nodeId int64, bytes int64) {
this.locker.Lock()
defer this.locker.Unlock()
// 先清理
var nowTime = time.Now().Unix()
this.gc(nowTime)
// 添加
var key = nodeType + "_" + types.String(nodeId)
this.nodeMap[key] = nowTime
// 流量
if this.rateTimestamp == nowTime {
this.rateBytes += bytes
} else {
this.rateTimestamp = nowTime
this.rateBytes = bytes
}
}
// CanUpgrade 检查是否有新的升级
func (this *UpgradeLimiter) CanUpgrade() bool {
this.locker.Lock()
defer this.locker.Unlock()
var nowTime = time.Now().Unix()
this.gc(nowTime)
// 限制并发节点数
if len(this.nodeMap) >= UpgradeLimiterConcurrent {
return false
}
if this.rateTimestamp != nowTime {
return true
}
// 限制下载速度
if this.rateBytes >= UpgradeLimiterMaxBytesPerSecond {
return false
}
return true
}
func (this *UpgradeLimiter) gc(nowTime int64) {
for nodeKey, timestamp := range this.nodeMap {
if timestamp < nowTime-UpgradeLimiterDuration {
delete(this.nodeMap, nodeKey)
}
}
}

View File

@@ -0,0 +1,27 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package installers_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/installers"
"github.com/TeaOSLab/EdgeAPI/internal/utils/sizes"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"testing"
"time"
)
func TestNewUpgradeLimiter(t *testing.T) {
var limiter = installers.NewUpgradeLimiter()
limiter.UpdateNodeBytes(nodeconfigs.NodeRoleNode, 1, 1)
limiter.UpdateNodeBytes(nodeconfigs.NodeRoleNode, 2, 5*sizes.M)
t.Log("limiter:", limiter)
t.Log("canUpgrade:", limiter.CanUpgrade())
time.Sleep(1 * time.Second)
t.Log("canUpgrade:", limiter.CanUpgrade())
t.Log("limiter:", limiter)
limiter.UpdateNodeBytes(nodeconfigs.NodeRoleNode, 2, 4*sizes.M)
t.Log("canUpgrade:", limiter.CanUpgrade())
t.Log("limiter:", limiter)
}

View File

@@ -3,8 +3,8 @@ package nodes
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/json"
"errors" "errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/accesslogs" "github.com/TeaOSLab/EdgeAPI/internal/accesslogs"
"github.com/TeaOSLab/EdgeAPI/internal/configs" "github.com/TeaOSLab/EdgeAPI/internal/configs"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
@@ -15,6 +15,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/rpc" "github.com/TeaOSLab/EdgeAPI/internal/rpc"
"github.com/TeaOSLab/EdgeAPI/internal/setup" "github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"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/lists" "github.com/iwind/TeaGo/lists"
@@ -35,6 +36,7 @@ import (
"runtime" "runtime"
"sort" "sort"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@@ -51,12 +53,18 @@ type APINode struct {
sock *gosock.Sock sock *gosock.Sock
isStarting bool isStarting bool
issues []*StartIssue
issuesFile string
} }
func NewAPINode() *APINode { func NewAPINode() *APINode {
return &APINode{ return &APINode{
serviceInstanceMap: map[string]interface{}{}, serviceInstanceMap: map[string]interface{}{},
sock: gosock.NewTmpSock(teaconst.ProcessName), sock: gosock.NewTmpSock(teaconst.ProcessName),
issues: []*StartIssue{},
issuesFile: Tea.LogFile("issues.log"),
} }
} }
@@ -65,18 +73,27 @@ func (this *APINode) Start() {
logs.Println("[API_NODE]start api node, pid: " + strconv.Itoa(os.Getpid())) logs.Println("[API_NODE]start api node, pid: " + strconv.Itoa(os.Getpid()))
// 检查数据库连接 // 保存启动过程中的问题,以便于查看
err := this.checkDB() defer func() {
if err != nil { this.saveIssues()
logs.Println("[API_NODE]" + err.Error()) }()
return
}
// 本地Sock // 本地Sock
logs.Println("[API_NODE]listening sock ...") logs.Println("[API_NODE]listening sock ...")
err = this.listenSock() err := this.listenSock()
if err != nil { if err != nil {
logs.Println("[API_NODE]" + err.Error()) var errString = "start local sock failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("sock", errString, "")
return
}
// 检查数据库连接
err = this.checkDB()
if err != nil {
var errString = "check database connection failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("db", errString, this.dbIssueSuggestion(err.Error()))
return return
} }
@@ -84,7 +101,9 @@ func (this *APINode) Start() {
logs.Println("[API_NODE]auto upgrading ...") logs.Println("[API_NODE]auto upgrading ...")
err = this.autoUpgrade() err = this.autoUpgrade()
if err != nil { if err != nil {
logs.Println("[API_NODE]auto upgrade failed: " + err.Error()) var errString = "auto upgrade failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("db", errString, this.dbIssueSuggestion(err.Error()))
return return
} }
@@ -105,7 +124,9 @@ func (this *APINode) Start() {
logs.Println("[API_NODE]reading api config ...") logs.Println("[API_NODE]reading api config ...")
config, err := configs.SharedAPIConfig() config, err := configs.SharedAPIConfig()
if err != nil { if err != nil {
logs.Println("[API_NODE]start failed: " + err.Error()) var errString = "read api config failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("config", errString, "")
return return
} }
sharedAPIConfig = config sharedAPIConfig = config
@@ -113,15 +134,23 @@ func (this *APINode) Start() {
// 校验 // 校验
apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINodeWithUniqueIdAndSecret(nil, config.NodeId, config.Secret) apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINodeWithUniqueIdAndSecret(nil, config.NodeId, config.Secret)
if err != nil { if err != nil {
logs.Println("[API_NODE]start failed: read api node from database failed: " + err.Error()) var errString = "start failed: read api node from database failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("db", errString, "")
return return
} }
if apiNode == nil { if apiNode == nil {
logs.Println("[API_NODE]can not start node, wrong 'nodeId' or 'secret'") var errString = "can not start node, wrong 'nodeId' or 'secret'"
logs.Println("[API_NODE]" + errString)
this.addStartIssue("config", errString, "请在api.yaml配置文件中填写正确的`nodeId`和`secret`如果数据库或者管理节点或API节点是从别的服务器迁移过来的请将老的系统配置拷贝到当前节点配置下")
return return
} }
config.SetNumberId(int64(apiNode.Id)) config.SetNumberId(int64(apiNode.Id))
// 清除上一次启动错误
// 这个错误文件可能不存在,不需要处理错误
_ = os.Remove(this.issuesFile)
// 设置rlimit // 设置rlimit
_ = utils.SetRLimit(1024 * 1024) _ = utils.SetRLimit(1024 * 1024)
@@ -138,10 +167,12 @@ func (this *APINode) Start() {
// 监听RPC服务 // 监听RPC服务
remotelogs.Println("API_NODE", "starting RPC server ...") remotelogs.Println("API_NODE", "starting RPC server ...")
isListening := this.listenPorts(apiNode) var isListening = this.listenPorts(apiNode)
if !isListening { if !isListening {
remotelogs.Error("API_NODE", "the api node require at least one listening address") var errString = "the api node require at least one listening address"
remotelogs.Error("API_NODE", errString)
this.addStartIssue("config", errString, "请给当前API节点设置一个监听端口")
return return
} }
@@ -154,9 +185,8 @@ func (this *APINode) Start() {
// Daemon 实现守护进程 // Daemon 实现守护进程
func (this *APINode) Daemon() { func (this *APINode) Daemon() {
path := os.TempDir() + "/edge-api.sock" var path = os.TempDir() + "/" + teaconst.ProcessName + ".sock"
isDebug := lists.ContainsString(os.Args, "debug") var isDebug = lists.ContainsString(os.Args, "debug")
isDebug = true
for { for {
conn, err := net.DialTimeout("unix", path, 1*time.Second) conn, err := net.DialTimeout("unix", path, 1*time.Second)
if err != nil { if err != nil {
@@ -199,14 +229,14 @@ func (this *APINode) Daemon() {
// InstallSystemService 安装系统服务 // InstallSystemService 安装系统服务
func (this *APINode) InstallSystemService() error { func (this *APINode) InstallSystemService() error {
shortName := teaconst.SystemdServiceName var shortName = teaconst.SystemdServiceName
exe, err := os.Executable() exe, err := os.Executable()
if err != nil { if err != nil {
return err return err
} }
manager := utils.NewServiceManager(shortName, teaconst.ProductName) var manager = utils.NewServiceManager(shortName, teaconst.ProductName)
err = manager.Install(exe, []string{}) err = manager.Install(exe, []string{})
if err != nil { if err != nil {
return err return err
@@ -242,21 +272,33 @@ func (this *APINode) checkDB() error {
return err return err
} }
maxTries := 600 // 第一次测试连接
for i := 0; i <= maxTries; i++ { _, err = db.Exec("SELECT 1")
_, err := db.Exec("SELECT 1") if err != nil {
if err != nil { var errString = "check database connection failed: " + err.Error()
if i == maxTries-1 { logs.Println("[API_NODE]" + errString)
return err this.addStartIssue("db", errString, this.dbIssueSuggestion(errString))
} else {
if i%10 == 0 { // 这让提示不会太多 // 多次尝试
logs.Println("[API_NODE]reconnecting to database (" + fmt.Sprintf("%.1f", float32(i*100)/float32(maxTries+1)) + "%) ...") var maxTries = 600
if Tea.IsTesting() {
maxTries = 600
}
for i := 0; i <= maxTries; i++ {
_, err := db.Exec("SELECT 1")
if err != nil {
if i == maxTries-1 {
return err
} else {
if i%10 == 0 { // 这让提示不会太多
logs.Println("[API_NODE]check database connection failed: " + err.Error() + ", reconnecting to database ...")
}
time.Sleep(1 * time.Second)
} }
time.Sleep(1 * time.Second) } else {
logs.Println("[API_NODE]database connected")
return nil
} }
} else {
logs.Println("[API_NODE]database connected")
return nil
} }
} }
@@ -270,7 +312,7 @@ func (this *APINode) autoUpgrade() error {
} }
// 执行SQL // 执行SQL
config := &dbs.Config{} var config = &dbs.Config{}
configData, err := ioutil.ReadFile(Tea.ConfigFile("db.yaml")) configData, err := ioutil.ReadFile(Tea.ConfigFile("db.yaml"))
if err != nil { if err != nil {
return errors.New("read database config file failed: " + err.Error()) return errors.New("read database config file failed: " + err.Error())
@@ -681,3 +723,62 @@ func (this *APINode) unaryInterceptor(ctx context.Context, req interface{}, info
} }
return result, err return result, err
} }
// 添加启动相关的Issue
func (this *APINode) addStartIssue(code string, message string, suggestion string) {
this.issues = append(this.issues, NewStartIssue(code, message, suggestion))
this.saveIssues()
}
// 增加数据库建议
func (this *APINode) dbIssueSuggestion(errString string) string {
// 数据库配置
db, err := dbs.Default()
if err != nil {
return ""
}
config, err := db.Config()
if err != nil {
return ""
}
var dsn = config.Dsn
dsnConfig, err := mysql.ParseDSN(dsn)
if err != nil {
return ""
}
var addr = dsnConfig.Addr
// 配置文件位置
var dbConfigPath = Tea.ConfigFile("db.yaml")
// 连接被拒绝
if strings.Contains(errString, "connection refused") {
// 本机
if strings.HasPrefix(addr, "127.0.0.1:") || strings.HasPrefix(addr, "localhost:") {
return "试图连接到数据库被拒绝请检查1本地数据库服务是否已经启动2数据库IP和端口" + addr + ")是否正确;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
} else {
return "试图连接到数据库被拒绝请检查1数据库服务是否已经启动2数据库IP和端口" + addr + "是否正确3防火墙设置当前数据库配置为" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
}
}
// 权限错误
if strings.Contains(errString, "Error 1045") || strings.Contains(errString, "Error 1044") {
return "使用的用户和密码没有权限连接到指定数据库请检查1数据库配置文件中的用户名" + dsnConfig.User + ")和密码(" + dsnConfig.Passwd + "是否正确2使用的用户是否已经在数据库中设置了正确的权限当前数据库配置为" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
}
// 数据库名称错误
if strings.Contains(errString, "Error 1049") {
return "数据库名称配置错误,请检查:数据库配置文件中数据库名称(" + dsnConfig.DBName + ")是否正确;(当前数据库配置为:" + dsn + ",配置文件位置:" + dbConfigPath + ")。"
}
return ""
}
// 保存issues
func (this *APINode) saveIssues() {
issuesJSON, err := json.Marshal(this.issues)
if err == nil {
_ = ioutil.WriteFile(this.issuesFile, issuesJSON, 0666)
}
}

View File

@@ -14,567 +14,590 @@ import (
// 注册服务 // 注册服务
func (this *APINode) registerServices(server *grpc.Server) { func (this *APINode) registerServices(server *grpc.Server) {
{ {
instance := this.serviceInstance(&services.APITokenService{}).(*services.APITokenService) var instance = this.serviceInstance(&services.APITokenService{}).(*services.APITokenService)
pb.RegisterAPITokenServiceServer(server, instance) pb.RegisterAPITokenServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.AdminService{}).(*services.AdminService) var instance = this.serviceInstance(&services.AdminService{}).(*services.AdminService)
pb.RegisterAdminServiceServer(server, instance) pb.RegisterAdminServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeGrantService{}).(*services.NodeGrantService) var instance = this.serviceInstance(&services.NodeGrantService{}).(*services.NodeGrantService)
pb.RegisterNodeGrantServiceServer(server, instance) pb.RegisterNodeGrantServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerService{}).(*services.ServerService) var instance = this.serviceInstance(&services.ServerService{}).(*services.ServerService)
pb.RegisterServerServiceServer(server, instance) pb.RegisterServerServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeService{}).(*services.NodeService) var instance = this.serviceInstance(&services.NodeService{}).(*services.NodeService)
pb.RegisterNodeServiceServer(server, instance) pb.RegisterNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeClusterService{}).(*services.NodeClusterService) var instance = this.serviceInstance(&services.NodeClusterService{}).(*services.NodeClusterService)
pb.RegisterNodeClusterServiceServer(server, instance) pb.RegisterNodeClusterServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeIPAddressService{}).(*services.NodeIPAddressService) var instance = this.serviceInstance(&services.NodeIPAddressService{}).(*services.NodeIPAddressService)
pb.RegisterNodeIPAddressServiceServer(server, instance) pb.RegisterNodeIPAddressServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeIPAddressLogService{}).(*services.NodeIPAddressLogService) var instance = this.serviceInstance(&services.NodeIPAddressLogService{}).(*services.NodeIPAddressLogService)
pb.RegisterNodeIPAddressLogServiceServer(server, instance) pb.RegisterNodeIPAddressLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeIPAddressThresholdService{}).(*services.NodeIPAddressThresholdService) var instance = this.serviceInstance(&services.NodeIPAddressThresholdService{}).(*services.NodeIPAddressThresholdService)
pb.RegisterNodeIPAddressThresholdServiceServer(server, instance) pb.RegisterNodeIPAddressThresholdServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.APINodeService{}).(*services.APINodeService) var instance = this.serviceInstance(&services.APINodeService{}).(*services.APINodeService)
pb.RegisterAPINodeServiceServer(server, instance) pb.RegisterAPINodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService) var instance = this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService)
pb.RegisterAPIMethodStatServiceServer(server, instance) pb.RegisterAPIMethodStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.OriginService{}).(*services.OriginService) var instance = this.serviceInstance(&services.OriginService{}).(*services.OriginService)
pb.RegisterOriginServiceServer(server, instance) pb.RegisterOriginServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPWebService{}).(*services.HTTPWebService) var instance = this.serviceInstance(&services.HTTPWebService{}).(*services.HTTPWebService)
pb.RegisterHTTPWebServiceServer(server, instance) pb.RegisterHTTPWebServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ReverseProxyService{}).(*services.ReverseProxyService) var instance = this.serviceInstance(&services.ReverseProxyService{}).(*services.ReverseProxyService)
pb.RegisterReverseProxyServiceServer(server, instance) pb.RegisterReverseProxyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPGzipService{}).(*services.HTTPGzipService) var instance = this.serviceInstance(&services.HTTPGzipService{}).(*services.HTTPGzipService)
pb.RegisterHTTPGzipServiceServer(server, instance) pb.RegisterHTTPGzipServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPHeaderPolicyService{}).(*services.HTTPHeaderPolicyService) var instance = this.serviceInstance(&services.HTTPHeaderPolicyService{}).(*services.HTTPHeaderPolicyService)
pb.RegisterHTTPHeaderPolicyServiceServer(server, instance) pb.RegisterHTTPHeaderPolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPHeaderService{}).(*services.HTTPHeaderService) var instance = this.serviceInstance(&services.HTTPHeaderService{}).(*services.HTTPHeaderService)
pb.RegisterHTTPHeaderServiceServer(server, instance) pb.RegisterHTTPHeaderServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPPageService{}).(*services.HTTPPageService) var instance = this.serviceInstance(&services.HTTPPageService{}).(*services.HTTPPageService)
pb.RegisterHTTPPageServiceServer(server, instance) pb.RegisterHTTPPageServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPAccessLogPolicyService{}).(*services.HTTPAccessLogPolicyService) var instance = this.serviceInstance(&services.HTTPAccessLogPolicyService{}).(*services.HTTPAccessLogPolicyService)
pb.RegisterHTTPAccessLogPolicyServiceServer(server, instance) pb.RegisterHTTPAccessLogPolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPCachePolicyService{}).(*services.HTTPCachePolicyService) var instance = this.serviceInstance(&services.HTTPCachePolicyService{}).(*services.HTTPCachePolicyService)
pb.RegisterHTTPCachePolicyServiceServer(server, instance) pb.RegisterHTTPCachePolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPFirewallPolicyService{}).(*services.HTTPFirewallPolicyService) var instance = this.serviceInstance(&services.HTTPFirewallPolicyService{}).(*services.HTTPFirewallPolicyService)
pb.RegisterHTTPFirewallPolicyServiceServer(server, instance) pb.RegisterHTTPFirewallPolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.FirewallService{}).(*services.FirewallService) var instance = this.serviceInstance(&services.FirewallService{}).(*services.FirewallService)
pb.RegisterFirewallServiceServer(server, instance) pb.RegisterFirewallServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPLocationService{}).(*services.HTTPLocationService) var instance = this.serviceInstance(&services.HTTPLocationService{}).(*services.HTTPLocationService)
pb.RegisterHTTPLocationServiceServer(server, instance) pb.RegisterHTTPLocationServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPWebsocketService{}).(*services.HTTPWebsocketService) var instance = this.serviceInstance(&services.HTTPWebsocketService{}).(*services.HTTPWebsocketService)
pb.RegisterHTTPWebsocketServiceServer(server, instance) pb.RegisterHTTPWebsocketServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPRewriteRuleService{}).(*services.HTTPRewriteRuleService) var instance = this.serviceInstance(&services.HTTPRewriteRuleService{}).(*services.HTTPRewriteRuleService)
pb.RegisterHTTPRewriteRuleServiceServer(server, instance) pb.RegisterHTTPRewriteRuleServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.SSLCertService{}).(*services.SSLCertService) var instance = this.serviceInstance(&services.SSLCertService{}).(*services.SSLCertService)
pb.RegisterSSLCertServiceServer(server, instance) pb.RegisterSSLCertServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.SSLPolicyService{}).(*services.SSLPolicyService) var instance = this.serviceInstance(&services.SSLPolicyService{}).(*services.SSLPolicyService)
pb.RegisterSSLPolicyServiceServer(server, instance) pb.RegisterSSLPolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.SysSettingService{}).(*services.SysSettingService) var instance = this.serviceInstance(&services.SysSettingService{}).(*services.SysSettingService)
pb.RegisterSysSettingServiceServer(server, instance) pb.RegisterSysSettingServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPFirewallRuleGroupService{}).(*services.HTTPFirewallRuleGroupService) var instance = this.serviceInstance(&services.HTTPFirewallRuleGroupService{}).(*services.HTTPFirewallRuleGroupService)
pb.RegisterHTTPFirewallRuleGroupServiceServer(server, instance) pb.RegisterHTTPFirewallRuleGroupServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPFirewallRuleSetService{}).(*services.HTTPFirewallRuleSetService) var instance = this.serviceInstance(&services.HTTPFirewallRuleSetService{}).(*services.HTTPFirewallRuleSetService)
pb.RegisterHTTPFirewallRuleSetServiceServer(server, instance) pb.RegisterHTTPFirewallRuleSetServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DBNodeService{}).(*services.DBNodeService) var instance = this.serviceInstance(&services.DBNodeService{}).(*services.DBNodeService)
pb.RegisterDBNodeServiceServer(server, instance) pb.RegisterDBNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeLogService{}).(*services.NodeLogService) var instance = this.serviceInstance(&services.NodeLogService{}).(*services.NodeLogService)
pb.RegisterNodeLogServiceServer(server, instance) pb.RegisterNodeLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeLoginService{}).(*services.NodeLoginService) var instance = this.serviceInstance(&services.NodeLoginService{}).(*services.NodeLoginService)
pb.RegisterNodeLoginServiceServer(server, instance) pb.RegisterNodeLoginServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPAccessLogService{}).(*services.HTTPAccessLogService) var instance = this.serviceInstance(&services.HTTPAccessLogService{}).(*services.HTTPAccessLogService)
pb.RegisterHTTPAccessLogServiceServer(server, instance) pb.RegisterHTTPAccessLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageService{}).(*services.MessageService) var instance = this.serviceInstance(&services.MessageService{}).(*services.MessageService)
pb.RegisterMessageServiceServer(server, instance) pb.RegisterMessageServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageRecipientService{}).(*services.MessageRecipientService) var instance = this.serviceInstance(&services.MessageRecipientService{}).(*services.MessageRecipientService)
pb.RegisterMessageRecipientServiceServer(server, instance) pb.RegisterMessageRecipientServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageReceiverService{}).(*services.MessageReceiverService) var instance = this.serviceInstance(&services.MessageReceiverService{}).(*services.MessageReceiverService)
pb.RegisterMessageReceiverServiceServer(server, instance) pb.RegisterMessageReceiverServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageMediaService{}).(*services.MessageMediaService) var instance = this.serviceInstance(&services.MessageMediaService{}).(*services.MessageMediaService)
pb.RegisterMessageMediaServiceServer(server, instance) pb.RegisterMessageMediaServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageRecipientGroupService{}).(*services.MessageRecipientGroupService) var instance = this.serviceInstance(&services.MessageRecipientGroupService{}).(*services.MessageRecipientGroupService)
pb.RegisterMessageRecipientGroupServiceServer(server, instance) pb.RegisterMessageRecipientGroupServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageMediaInstanceService{}).(*services.MessageMediaInstanceService) var instance = this.serviceInstance(&services.MessageMediaInstanceService{}).(*services.MessageMediaInstanceService)
pb.RegisterMessageMediaInstanceServiceServer(server, instance) pb.RegisterMessageMediaInstanceServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageTaskService{}).(*services.MessageTaskService) var instance = this.serviceInstance(&services.MessageTaskService{}).(*services.MessageTaskService)
pb.RegisterMessageTaskServiceServer(server, instance) pb.RegisterMessageTaskServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MessageTaskLogService{}).(*services.MessageTaskLogService) var instance = this.serviceInstance(&services.MessageTaskLogService{}).(*services.MessageTaskLogService)
pb.RegisterMessageTaskLogServiceServer(server, instance) pb.RegisterMessageTaskLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeGroupService{}).(*services.NodeGroupService) var instance = this.serviceInstance(&services.NodeGroupService{}).(*services.NodeGroupService)
pb.RegisterNodeGroupServiceServer(server, instance) pb.RegisterNodeGroupServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeRegionService{}).(*services.NodeRegionService) var instance = this.serviceInstance(&services.NodeRegionService{}).(*services.NodeRegionService)
pb.RegisterNodeRegionServiceServer(server, instance) pb.RegisterNodeRegionServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodePriceItemService{}).(*services.NodePriceItemService) var instance = this.serviceInstance(&services.NodePriceItemService{}).(*services.NodePriceItemService)
pb.RegisterNodePriceItemServiceServer(server, instance) pb.RegisterNodePriceItemServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerGroupService{}).(*services.ServerGroupService) var instance = this.serviceInstance(&services.ServerGroupService{}).(*services.ServerGroupService)
pb.RegisterServerGroupServiceServer(server, instance) pb.RegisterServerGroupServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.IPLibraryService{}).(*services.IPLibraryService) var instance = this.serviceInstance(&services.IPLibraryService{}).(*services.IPLibraryService)
pb.RegisterIPLibraryServiceServer(server, instance) pb.RegisterIPLibraryServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService) var instance = this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
pb.RegisterFileChunkServiceServer(server, instance) pb.RegisterFileChunkServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.FileService{}).(*services.FileService) var instance = this.serviceInstance(&services.FileService{}).(*services.FileService)
pb.RegisterFileServiceServer(server, instance) pb.RegisterFileServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.RegionCountryService{}).(*services.RegionCountryService) var instance = this.serviceInstance(&services.RegionCountryService{}).(*services.RegionCountryService)
pb.RegisterRegionCountryServiceServer(server, instance) pb.RegisterRegionCountryServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.RegionProvinceService{}).(*services.RegionProvinceService) var instance = this.serviceInstance(&services.RegionProvinceService{}).(*services.RegionProvinceService)
pb.RegisterRegionProvinceServiceServer(server, instance) pb.RegisterRegionProvinceServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.RegionCityService{}).(*services.RegionCityService) var instance = this.serviceInstance(&services.RegionCityService{}).(*services.RegionCityService)
pb.RegisterRegionCityServiceServer(server, instance) pb.RegisterRegionCityServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.RegionProviderService{}).(*services.RegionProviderService) var instance = this.serviceInstance(&services.RegionProviderService{}).(*services.RegionProviderService)
pb.RegisterRegionProviderServiceServer(server, instance) pb.RegisterRegionProviderServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.IPListService{}).(*services.IPListService) var instance = this.serviceInstance(&services.IPListService{}).(*services.IPListService)
pb.RegisterIPListServiceServer(server, instance) pb.RegisterIPListServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.IPItemService{}).(*services.IPItemService) var instance = this.serviceInstance(&services.IPItemService{}).(*services.IPItemService)
pb.RegisterIPItemServiceServer(server, instance) pb.RegisterIPItemServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.LogService{}).(*services.LogService) var instance = this.serviceInstance(&services.LogService{}).(*services.LogService)
pb.RegisterLogServiceServer(server, instance) pb.RegisterLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DNSProviderService{}).(*services.DNSProviderService) var instance = this.serviceInstance(&services.DNSProviderService{}).(*services.DNSProviderService)
pb.RegisterDNSProviderServiceServer(server, instance) pb.RegisterDNSProviderServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DNSDomainService{}).(*services.DNSDomainService) var instance = this.serviceInstance(&services.DNSDomainService{}).(*services.DNSDomainService)
pb.RegisterDNSDomainServiceServer(server, instance) pb.RegisterDNSDomainServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DNSService{}).(*services.DNSService) var instance = this.serviceInstance(&services.DNSService{}).(*services.DNSService)
pb.RegisterDNSServiceServer(server, instance) pb.RegisterDNSServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ACMEUserService{}).(*services.ACMEUserService) var instance = this.serviceInstance(&services.ACMEUserService{}).(*services.ACMEUserService)
pb.RegisterACMEUserServiceServer(server, instance) pb.RegisterACMEUserServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ACMETaskService{}).(*services.ACMETaskService) var instance = this.serviceInstance(&services.ACMETaskService{}).(*services.ACMETaskService)
pb.RegisterACMETaskServiceServer(server, instance) pb.RegisterACMETaskServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ACMEAuthenticationService{}).(*services.ACMEAuthenticationService) var instance = this.serviceInstance(&services.ACMEAuthenticationService{}).(*services.ACMEAuthenticationService)
pb.RegisterACMEAuthenticationServiceServer(server, instance) pb.RegisterACMEAuthenticationServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ACMEProviderService{}).(*services.ACMEProviderService) var instance = this.serviceInstance(&services.ACMEProviderService{}).(*services.ACMEProviderService)
pb.RegisterACMEProviderServiceServer(server, instance) pb.RegisterACMEProviderServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ACMEProviderAccountService{}).(*services.ACMEProviderAccountService) var instance = this.serviceInstance(&services.ACMEProviderAccountService{}).(*services.ACMEProviderAccountService)
pb.RegisterACMEProviderAccountServiceServer(server, instance) pb.RegisterACMEProviderAccountServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.UserService{}).(*services.UserService) var instance = this.serviceInstance(&services.UserService{}).(*services.UserService)
pb.RegisterUserServiceServer(server, instance) pb.RegisterUserServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerDailyStatService{}).(*services.ServerDailyStatService) var instance = this.serviceInstance(&services.UserIdentityService{}).(*services.UserIdentityService)
pb.RegisterUserIdentityServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.ServerDailyStatService{}).(*services.ServerDailyStatService)
pb.RegisterServerDailyStatServiceServer(server, instance) pb.RegisterServerDailyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.UserBillService{}).(*services.UserBillService) var instance = this.serviceInstance(&services.UserBillService{}).(*services.UserBillService)
pb.RegisterUserBillServiceServer(server, instance) pb.RegisterUserBillServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService) var instance = this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
pb.RegisterServerBillServiceServer(server, instance) pb.RegisterServerBillServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService) var instance = this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
pb.RegisterUserNodeServiceServer(server, instance) pb.RegisterUserNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.LoginService{}).(*services.LoginService) var instance = this.serviceInstance(&services.LoginService{}).(*services.LoginService)
pb.RegisterLoginServiceServer(server, instance) pb.RegisterLoginServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.UserAccessKeyService{}).(*services.UserAccessKeyService) var instance = this.serviceInstance(&services.UserAccessKeyService{}).(*services.UserAccessKeyService)
pb.RegisterUserAccessKeyServiceServer(server, instance) pb.RegisterUserAccessKeyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.SysLockerService{}).(*services.SysLockerService) var instance = this.serviceInstance(&services.SysLockerService{}).(*services.SysLockerService)
pb.RegisterSysLockerServiceServer(server, instance) pb.RegisterSysLockerServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeTaskService{}).(*services.NodeTaskService) var instance = this.serviceInstance(&services.NodeTaskService{}).(*services.NodeTaskService)
pb.RegisterNodeTaskServiceServer(server, instance) pb.RegisterNodeTaskServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeValueService{}).(*services.NodeValueService) var instance = this.serviceInstance(&services.NodeValueService{}).(*services.NodeValueService)
pb.RegisterNodeValueServiceServer(server, instance) pb.RegisterNodeValueServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DBService{}).(*services.DBService) var instance = this.serviceInstance(&services.DBService{}).(*services.DBService)
pb.RegisterDBServiceServer(server, instance) pb.RegisterDBServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerRegionCityMonthlyStatService{}).(*services.ServerRegionCityMonthlyStatService) var instance = this.serviceInstance(&services.ServerRegionCityMonthlyStatService{}).(*services.ServerRegionCityMonthlyStatService)
pb.RegisterServerRegionCityMonthlyStatServiceServer(server, instance) pb.RegisterServerRegionCityMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerRegionCountryMonthlyStatService{}).(*services.ServerRegionCountryMonthlyStatService) var instance = this.serviceInstance(&services.ServerRegionCountryMonthlyStatService{}).(*services.ServerRegionCountryMonthlyStatService)
pb.RegisterServerRegionCountryMonthlyStatServiceServer(server, instance) pb.RegisterServerRegionCountryMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerRegionProvinceMonthlyStatService{}).(*services.ServerRegionProvinceMonthlyStatService) var instance = this.serviceInstance(&services.ServerRegionProvinceMonthlyStatService{}).(*services.ServerRegionProvinceMonthlyStatService)
pb.RegisterServerRegionProvinceMonthlyStatServiceServer(server, instance) pb.RegisterServerRegionProvinceMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerRegionProviderMonthlyStatService{}).(*services.ServerRegionProviderMonthlyStatService) var instance = this.serviceInstance(&services.ServerRegionProviderMonthlyStatService{}).(*services.ServerRegionProviderMonthlyStatService)
pb.RegisterServerRegionProviderMonthlyStatServiceServer(server, instance) pb.RegisterServerRegionProviderMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService) var instance = this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService)
pb.RegisterServerClientSystemMonthlyStatServiceServer(server, instance) pb.RegisterServerClientSystemMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerClientBrowserMonthlyStatService{}).(*services.ServerClientBrowserMonthlyStatService) var instance = this.serviceInstance(&services.ServerClientBrowserMonthlyStatService{}).(*services.ServerClientBrowserMonthlyStatService)
pb.RegisterServerClientBrowserMonthlyStatServiceServer(server, instance) pb.RegisterServerClientBrowserMonthlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerHTTPFirewallDailyStatService{}).(*services.ServerHTTPFirewallDailyStatService) var instance = this.serviceInstance(&services.ServerHTTPFirewallDailyStatService{}).(*services.ServerHTTPFirewallDailyStatService)
pb.RegisterServerHTTPFirewallDailyStatServiceServer(server, instance) pb.RegisterServerHTTPFirewallDailyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.DNSTaskService{}).(*services.DNSTaskService) var instance = this.serviceInstance(&services.DNSTaskService{}).(*services.DNSTaskService)
pb.RegisterDNSTaskServiceServer(server, instance) pb.RegisterDNSTaskServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeClusterFirewallActionService{}).(*services.NodeClusterFirewallActionService) var instance = this.serviceInstance(&services.NodeClusterFirewallActionService{}).(*services.NodeClusterFirewallActionService)
pb.RegisterNodeClusterFirewallActionServiceServer(server, instance) pb.RegisterNodeClusterFirewallActionServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MonitorNodeService{}).(*services.MonitorNodeService) var instance = this.serviceInstance(&services.MonitorNodeService{}).(*services.MonitorNodeService)
pb.RegisterMonitorNodeServiceServer(server, instance) pb.RegisterMonitorNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.AuthorityNodeService{}).(*services.AuthorityNodeService) var instance = this.serviceInstance(&services.AuthorityNodeService{}).(*services.AuthorityNodeService)
pb.RegisterAuthorityNodeServiceServer(server, instance) pb.RegisterAuthorityNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.LatestItemService{}).(*services.LatestItemService) var instance = this.serviceInstance(&services.LatestItemService{}).(*services.LatestItemService)
pb.RegisterLatestItemServiceServer(server, instance) pb.RegisterLatestItemServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeThresholdService{}).(*services.NodeThresholdService) var instance = this.serviceInstance(&services.NodeThresholdService{}).(*services.NodeThresholdService)
pb.RegisterNodeThresholdServiceServer(server, instance) pb.RegisterNodeThresholdServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPFastcgiService{}).(*services.HTTPFastcgiService) var instance = this.serviceInstance(&services.HTTPFastcgiService{}).(*services.HTTPFastcgiService)
pb.RegisterHTTPFastcgiServiceServer(server, instance) pb.RegisterHTTPFastcgiServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSClusterService{}).(*nameservers.NSClusterService) var instance = this.serviceInstance(&nameservers.NSClusterService{}).(*nameservers.NSClusterService)
pb.RegisterNSClusterServiceServer(server, instance) pb.RegisterNSClusterServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSNodeService{}).(*nameservers.NSNodeService) var instance = this.serviceInstance(&nameservers.NSNodeService{}).(*nameservers.NSNodeService)
pb.RegisterNSNodeServiceServer(server, instance) pb.RegisterNSNodeServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSDomainService{}).(*nameservers.NSDomainService) var instance = this.serviceInstance(&nameservers.NSDomainService{}).(*nameservers.NSDomainService)
pb.RegisterNSDomainServiceServer(server, instance) pb.RegisterNSDomainServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSRecordService{}).(*nameservers.NSRecordService) var instance = this.serviceInstance(&nameservers.NSRecordService{}).(*nameservers.NSRecordService)
pb.RegisterNSRecordServiceServer(server, instance) pb.RegisterNSRecordServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSRouteService{}).(*nameservers.NSRouteService) var instance = this.serviceInstance(&nameservers.NSRouteService{}).(*nameservers.NSRouteService)
pb.RegisterNSRouteServiceServer(server, instance) pb.RegisterNSRouteServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSKeyService{}).(*nameservers.NSKeyService) var instance = this.serviceInstance(&nameservers.NSKeyService{}).(*nameservers.NSKeyService)
pb.RegisterNSKeyServiceServer(server, instance) pb.RegisterNSKeyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSAccessLogService{}).(*nameservers.NSAccessLogService) var instance = this.serviceInstance(&nameservers.NSAccessLogService{}).(*nameservers.NSAccessLogService)
pb.RegisterNSAccessLogServiceServer(server, instance) pb.RegisterNSAccessLogServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSRecordHourlyStatService{}).(*nameservers.NSRecordHourlyStatService) var instance = this.serviceInstance(&nameservers.NSRecordHourlyStatService{}).(*nameservers.NSRecordHourlyStatService)
pb.RegisterNSRecordHourlyStatServiceServer(server, instance) pb.RegisterNSRecordHourlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSQuestionOptionService{}).(*nameservers.NSQuestionOptionService) var instance = this.serviceInstance(&nameservers.NSQuestionOptionService{}).(*nameservers.NSQuestionOptionService)
pb.RegisterNSQuestionOptionServiceServer(server, instance) pb.RegisterNSQuestionOptionServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&nameservers.NSService{}).(*nameservers.NSService) var instance = this.serviceInstance(&nameservers.NSService{}).(*nameservers.NSService)
pb.RegisterNSServiceServer(server, instance) pb.RegisterNSServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.HTTPAuthPolicyService{}).(*services.HTTPAuthPolicyService) var instance = this.serviceInstance(&services.HTTPAuthPolicyService{}).(*services.HTTPAuthPolicyService)
pb.RegisterHTTPAuthPolicyServiceServer(server, instance) pb.RegisterHTTPAuthPolicyServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MetricItemService{}).(*services.MetricItemService) var instance = this.serviceInstance(&services.MetricItemService{}).(*services.MetricItemService)
pb.RegisterMetricItemServiceServer(server, instance) pb.RegisterMetricItemServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.NodeClusterMetricItemService{}).(*services.NodeClusterMetricItemService) var instance = this.serviceInstance(&services.NodeClusterMetricItemService{}).(*services.NodeClusterMetricItemService)
pb.RegisterNodeClusterMetricItemServiceServer(server, instance) pb.RegisterNodeClusterMetricItemServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MetricStatService{}).(*services.MetricStatService) var instance = this.serviceInstance(&services.MetricStatService{}).(*services.MetricStatService)
pb.RegisterMetricStatServiceServer(server, instance) pb.RegisterMetricStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.MetricChartService{}).(*services.MetricChartService) var instance = this.serviceInstance(&services.MetricChartService{}).(*services.MetricChartService)
pb.RegisterMetricChartServiceServer(server, instance) pb.RegisterMetricChartServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerStatBoardService{}).(*services.ServerStatBoardService) var instance = this.serviceInstance(&services.ServerStatBoardService{}).(*services.ServerStatBoardService)
pb.RegisterServerStatBoardServiceServer(server, instance) pb.RegisterServerStatBoardServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerStatBoardChartService{}).(*services.ServerStatBoardChartService) var instance = this.serviceInstance(&services.ServerStatBoardChartService{}).(*services.ServerStatBoardChartService)
pb.RegisterServerStatBoardChartServiceServer(server, instance) pb.RegisterServerStatBoardChartServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.PlanService{}).(*services.PlanService) var instance = this.serviceInstance(&services.PlanService{}).(*services.PlanService)
pb.RegisterPlanServiceServer(server, instance) pb.RegisterPlanServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.UserPlanService{}).(*services.UserPlanService) var instance = this.serviceInstance(&services.UserPlanService{}).(*services.UserPlanService)
pb.RegisterUserPlanServiceServer(server, instance) pb.RegisterUserPlanServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.ServerDomainHourlyStatService{}).(*services.ServerDomainHourlyStatService) var instance = this.serviceInstance(&services.ServerDomainHourlyStatService{}).(*services.ServerDomainHourlyStatService)
pb.RegisterServerDomainHourlyStatServiceServer(server, instance) pb.RegisterServerDomainHourlyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{ {
instance := this.serviceInstance(&services.TrafficDailyStatService{}).(*services.TrafficDailyStatService) var instance = this.serviceInstance(&services.TrafficDailyStatService{}).(*services.TrafficDailyStatService)
pb.RegisterTrafficDailyStatServiceServer(server, instance) pb.RegisterTrafficDailyStatServiceServer(server, instance)
this.rest(instance) this.rest(instance)
} }
{
var instance = this.serviceInstance(&services.HTTPCacheTaskKeyService{}).(*services.HTTPCacheTaskKeyService)
pb.RegisterHTTPCacheTaskKeyServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.HTTPCacheTaskService{}).(*services.HTTPCacheTaskService)
pb.RegisterHTTPCacheTaskServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.ServerBandwidthStatService{}).(*services.ServerBandwidthStatService)
pb.RegisterServerBandwidthStatServiceServer(server, instance)
this.rest(instance)
}
APINodeServicesRegister(this, server) APINodeServicesRegister(this, server)
// TODO check service names // TODO check service names
for serviceName := range server.GetServiceInfo() { for serviceName := range server.GetServiceInfo() {
index := strings.LastIndex(serviceName, ".") var index = strings.LastIndex(serviceName, ".")
if index >= 0 { if index >= 0 {
serviceName = serviceName[index+1:] serviceName = serviceName[index+1:]
} }
@@ -590,7 +613,7 @@ func (this *APINode) rest(instance interface{}) {
defer this.serviceInstanceLocker.Unlock() defer this.serviceInstanceLocker.Unlock()
var name = reflect.TypeOf(instance).String() var name = reflect.TypeOf(instance).String()
index := strings.LastIndex(name, ".") var index = strings.LastIndex(name, ".")
if index >= 0 { if index >= 0 {
name = name[index+1:] name = name[index+1:]
} }
@@ -606,7 +629,7 @@ func (this *APINode) serviceInstance(instance interface{}) interface{} {
this.serviceInstanceLocker.Lock() this.serviceInstanceLocker.Lock()
defer this.serviceInstanceLocker.Unlock() defer this.serviceInstanceLocker.Unlock()
typeName := reflect.TypeOf(instance).String() var typeName = reflect.TypeOf(instance).String()
result, ok := this.serviceInstanceMap[typeName] result, ok := this.serviceInstanceMap[typeName]
if ok { if ok {
return result return result

View File

@@ -0,0 +1,17 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodes
type StartIssue struct {
Code string `json:"code"`
Message string `json:"message"`
Suggestion string `json:"suggestion"`
}
func NewStartIssue(code string, message string, suggestion string) *StartIssue {
return &StartIssue{
Code: code,
Message: message,
Suggestion: suggestion,
}
}

View File

@@ -18,6 +18,7 @@ import (
stringutil "github.com/iwind/TeaGo/utils/string" stringutil "github.com/iwind/TeaGo/utils/string"
"io" "io"
"path/filepath" "path/filepath"
"time"
) )
// NSNodeService 域名服务器节点服务 // NSNodeService 域名服务器节点服务
@@ -398,9 +399,18 @@ func (this *NSNodeService) UpdateNSNodeStatus(ctx context.Context, req *pb.Updat
return nil, errors.New("'nodeId' should be greater than 0") return nil, errors.New("'nodeId' should be greater than 0")
} }
tx := this.NullTx() var tx = this.NullTx()
err = models.SharedNSNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON) // 修改时间戳
var nodeStatus = &nodeconfigs.NodeStatus{}
err = json.Unmarshal(req.StatusJSON, nodeStatus)
if err != nil {
return nil, errors.New("decode node status json failed: " + err.Error())
}
nodeStatus.UpdatedAt = time.Now().Unix()
// 保存
err = models.SharedNSNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -452,12 +462,12 @@ func (this *NSNodeService) CheckNSNodeLatestVersion(ctx context.Context, req *pb
// DownloadNSNodeInstallationFile 下载最新DNS节点安装文件 // DownloadNSNodeInstallationFile 下载最新DNS节点安装文件
func (this *NSNodeService) DownloadNSNodeInstallationFile(ctx context.Context, req *pb.DownloadNSNodeInstallationFileRequest) (*pb.DownloadNSNodeInstallationFileResponse, error) { func (this *NSNodeService) DownloadNSNodeInstallationFile(ctx context.Context, req *pb.DownloadNSNodeInstallationFileRequest) (*pb.DownloadNSNodeInstallationFileResponse, error) {
_, err := this.ValidateNSNode(ctx) nodeId, err := this.ValidateNSNode(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
file := installers.SharedDeployManager.FindNSNodeFile(req.Os, req.Arch) var file = installers.SharedDeployManager.FindNSNodeFile(req.Os, req.Arch)
if file == nil { if file == nil {
return &pb.DownloadNSNodeInstallationFileResponse{}, nil return &pb.DownloadNSNodeInstallationFileResponse{}, nil
} }
@@ -472,6 +482,9 @@ func (this *NSNodeService) DownloadNSNodeInstallationFile(ctx context.Context, r
return nil, err return nil, err
} }
// 增加下载速度监控
installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleDNS, nodeId, int64(len(data)))
return &pb.DownloadNSNodeInstallationFileResponse{ return &pb.DownloadNSNodeInstallationFileResponse{
Sum: sum, Sum: sum,
Offset: offset, Offset: offset,

View File

@@ -2,11 +2,14 @@ package services
import ( import (
"context" "context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority" "github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"time"
) )
type AuthorityNodeService struct { type AuthorityNodeService struct {
@@ -223,9 +226,18 @@ func (this *AuthorityNodeService) UpdateAuthorityNodeStatus(ctx context.Context,
return nil, errors.New("'nodeId' should be greater than 0") return nil, errors.New("'nodeId' should be greater than 0")
} }
tx := this.NullTx() var tx = this.NullTx()
err = authority.SharedAuthorityNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON) // 修改时间戳
var nodeStatus = &nodeconfigs.NodeStatus{}
err = json.Unmarshal(req.StatusJSON, nodeStatus)
if err != nil {
return nil, errors.New("decode node status json failed: " + err.Error())
}
nodeStatus.UpdatedAt = time.Now().Unix()
// 保存
err = authority.SharedAuthorityNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -59,7 +59,7 @@ func (this *DNSProviderService) CountAllEnabledDNSProviders(ctx context.Context,
tx := this.NullTx() tx := this.NullTx()
count, err := dns.SharedDNSProviderDAO.CountAllEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain) count, err := dns.SharedDNSProviderDAO.CountAllEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Type)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,9 +76,9 @@ func (this *DNSProviderService) ListEnabledDNSProviders(ctx context.Context, req
// TODO 校验权限 // TODO 校验权限
tx := this.NullTx() var tx = this.NullTx()
providers, err := dns.SharedDNSProviderDAO.ListEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Offset, req.Size) providers, err := dns.SharedDNSProviderDAO.ListEnabledDNSProviders(tx, req.AdminId, req.UserId, req.Keyword, req.Domain, req.Type, req.Offset, req.Size)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -0,0 +1,383 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
)
// HTTPCacheTaskService 缓存任务管理
type HTTPCacheTaskService struct {
BaseService
}
// CreateHTTPCacheTask 创建任务
func (this *HTTPCacheTaskService) CreateHTTPCacheTask(ctx context.Context, req *pb.CreateHTTPCacheTaskRequest) (*pb.CreateHTTPCacheTaskResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查操作类型
if req.Type != models.HTTPCacheTaskTypePurge && req.Type != models.HTTPCacheTaskTypeFetch {
return nil, errors.New("invalid type '" + req.Type + "'")
}
// 检查Key数量
var clusterId int64
if userId > 0 {
// 限制单次
var maxKeysPerTask = userconfigs.MaxCacheKeysPerTask
var maxKeysPerDay = userconfigs.MaxCacheKeysPerDay
serverConfig, err := models.SharedSysSettingDAO.ReadUserServerConfig(tx)
if err != nil {
return nil, err
}
if serverConfig != nil {
switch req.Type {
case models.HTTPCacheTaskTypePurge:
if serverConfig.HTTPCacheTaskPurgeConfig != nil {
if serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerTask > 0 {
maxKeysPerTask = serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerTask
}
if serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerDay > 0 {
maxKeysPerDay = serverConfig.HTTPCacheTaskPurgeConfig.MaxKeysPerDay
}
}
case models.HTTPCacheTaskTypeFetch:
if serverConfig.HTTPCacheTaskFetchConfig != nil {
if serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerTask > 0 {
maxKeysPerTask = serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerTask
}
if serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerDay > 0 {
maxKeysPerDay = serverConfig.HTTPCacheTaskFetchConfig.MaxKeysPerDay
}
}
}
}
if maxKeysPerTask > 0 && len(req.Keys) > types.Int(maxKeysPerTask) {
return nil, errors.New("too many keys in task (current:" + types.String(len(req.Keys)) + ", max:" + types.String(maxKeysPerTask) + ")")
}
if maxKeysPerDay > 0 {
countInDay, err := models.SharedHTTPCacheTaskKeyDAO.CountUserTasksInDay(tx, userId, timeutil.Format("Ymd"), req.Type)
if err != nil {
return nil, err
}
if types.Int(countInDay)+len(req.Keys) > types.Int(maxKeysPerDay) {
return nil, errors.New("too many keys in today (current:" + types.String(types.Int(countInDay)+len(req.Keys)) + ", max:" + types.String(maxKeysPerDay) + ")")
}
}
clusterId, err = models.SharedUserDAO.FindUserClusterId(tx, userId)
if err != nil {
return nil, err
}
}
// 创建任务
taskId, err := models.SharedHTTPCacheTaskDAO.CreateTask(tx, userId, req.Type, req.KeyType, "")
if err != nil {
return nil, err
}
var countKeys = 0
var domainMap = map[string]*models.Server{} // domain name => *Server
for _, key := range req.Keys {
if len(key) == 0 {
continue
}
// 获取域名
var domain = utils.ParseDomainFromKey(key)
if len(domain) == 0 {
continue
}
// 查询所在集群
server, ok := domainMap[domain]
if !ok {
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
if err != nil {
return nil, err
}
if server == nil {
continue
}
domainMap[domain] = server
}
// 检查用户
if userId > 0 {
if int64(server.UserId) != userId {
continue
}
}
var serverClusterId = int64(server.ClusterId)
if serverClusterId == 0 {
if clusterId > 0 {
serverClusterId = clusterId
} else {
continue
}
}
_, err = models.SharedHTTPCacheTaskKeyDAO.CreateKey(tx, taskId, key, req.Type, req.KeyType, serverClusterId)
if err != nil {
return nil, err
}
countKeys++
}
if countKeys == 0 {
// 如果没有有效的Key则直接完成
err = models.SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, true, true)
} else {
err = models.SharedHTTPCacheTaskDAO.UpdateTaskReady(tx, taskId)
}
if err != nil {
return nil, err
}
return &pb.CreateHTTPCacheTaskResponse{
HttpCacheTaskId: taskId,
CountKeys: int64(countKeys),
}, nil
}
// CountHTTPCacheTasks 计算任务数量
func (this *HTTPCacheTaskService) CountHTTPCacheTasks(ctx context.Context, req *pb.CountHTTPCacheTasksRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedHTTPCacheTaskDAO.CountTasks(tx, userId)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// CountDoingHTTPCacheTasks 计算正在执行的任务数量
func (this *HTTPCacheTaskService) CountDoingHTTPCacheTasks(ctx context.Context, req *pb.CountDoingHTTPCacheTasksRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := models.SharedHTTPCacheTaskDAO.CountDoingTasks(tx, userId)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListHTTPCacheTasks 列出单页任务
func (this *HTTPCacheTaskService) ListHTTPCacheTasks(ctx context.Context, req *pb.ListHTTPCacheTasksRequest) (*pb.ListHTTPCacheTasksResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
tasks, err := models.SharedHTTPCacheTaskDAO.ListTasks(tx, userId, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbTasks = []*pb.HTTPCacheTask{}
var cacheMap = utils.NewCacheMap()
for _, task := range tasks {
var taskId = int64(task.Id)
// 查询所属用户
var pbUser = &pb.User{}
if task.UserId > 0 {
var taskUserId = int64(task.UserId)
if taskUserId > 0 {
taskUser, err := models.SharedUserDAO.FindEnabledUser(tx, taskUserId, cacheMap)
if err != nil {
return nil, err
}
if taskUser == nil {
// 找不到用户就删除
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, taskUserId)
if err != nil {
return nil, err
}
} else {
pbUser = &pb.User{
Id: int64(taskUser.Id),
Username: taskUser.Username,
Fullname: taskUser.Fullname,
}
}
}
}
pbTasks = append(pbTasks, &pb.HTTPCacheTask{
Id: taskId,
UserId: int64(task.UserId),
Type: task.Type,
KeyType: task.KeyType,
CreatedAt: int64(task.CreatedAt),
DoneAt: int64(task.DoneAt),
IsDone: task.IsDone,
IsOk: task.IsOk,
Description: task.Description,
User: pbUser,
HttpCacheTaskKeys: nil,
})
}
return &pb.ListHTTPCacheTasksResponse{
HttpCacheTasks: pbTasks,
}, nil
}
// FindEnabledHTTPCacheTask 查找单个任务
func (this *HTTPCacheTaskService) FindEnabledHTTPCacheTask(ctx context.Context, req *pb.FindEnabledHTTPCacheTaskRequest) (*pb.FindEnabledHTTPCacheTaskResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedHTTPCacheTaskDAO.CheckUserTask(tx, userId, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
}
task, err := models.SharedHTTPCacheTaskDAO.FindEnabledHTTPCacheTask(tx, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
if task == nil {
return &pb.FindEnabledHTTPCacheTaskResponse{HttpCacheTask: nil}, nil
}
// 查询所属用户
var pbUser = &pb.User{}
if task.UserId > 0 {
var taskUserId = int64(task.UserId)
if taskUserId > 0 {
taskUser, err := models.SharedUserDAO.FindEnabledUser(tx, taskUserId, nil)
if err != nil {
return nil, err
}
if taskUser == nil {
// 找不到用户就删除
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, taskUserId)
if err != nil {
return nil, err
}
} else {
pbUser = &pb.User{
Id: int64(taskUser.Id),
Username: taskUser.Username,
Fullname: taskUser.Fullname,
}
}
}
}
// Keys
keys, err := models.SharedHTTPCacheTaskKeyDAO.FindAllTaskKeys(tx, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
var pbKeys = []*pb.HTTPCacheTaskKey{}
for _, key := range keys {
pbKeys = append(pbKeys, &pb.HTTPCacheTaskKey{
Id: int64(key.Id),
TaskId: int64(key.TaskId),
Key: key.Key,
KeyType: key.KeyType,
IsDone: key.IsDone,
IsDoing: !key.IsDone && len(key.DecodeNodes()) > 0,
ErrorsJSON: key.Errors,
})
}
return &pb.FindEnabledHTTPCacheTaskResponse{
HttpCacheTask: &pb.HTTPCacheTask{
Id: int64(task.Id),
UserId: int64(task.UserId),
Type: task.Type,
KeyType: task.KeyType,
CreatedAt: int64(task.CreatedAt),
DoneAt: int64(task.DoneAt),
IsDone: task.IsDone,
IsOk: task.IsOk,
User: pbUser,
HttpCacheTaskKeys: pbKeys,
},
}, nil
}
// DeleteHTTPCacheTask 删除任务
func (this *HTTPCacheTaskService) DeleteHTTPCacheTask(ctx context.Context, req *pb.DeleteHTTPCacheTaskRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedHTTPCacheTaskDAO.CheckUserTask(tx, userId, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
}
err = models.SharedHTTPCacheTaskDAO.DisableHTTPCacheTask(tx, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
return this.Success()
}
// ResetHTTPCacheTask 重置任务状态
// 只允许管理员重置,用于调试
func (this *HTTPCacheTaskService) ResetHTTPCacheTask(ctx context.Context, req *pb.ResetHTTPCacheTaskRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 重置任务
err = models.SharedHTTPCacheTaskDAO.ResetTask(tx, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
// 重置任务下的Key
err = models.SharedHTTPCacheTaskKeyDAO.ResetCacheKeysWithTaskId(tx, req.HttpCacheTaskId)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -0,0 +1,173 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
)
// HTTPCacheTaskKeyService 缓存任务Key管理
type HTTPCacheTaskKeyService struct {
BaseService
}
// ValidateHTTPCacheTaskKeys 校验缓存Key
func (this *HTTPCacheTaskKeyService) ValidateHTTPCacheTaskKeys(ctx context.Context, req *pb.ValidateHTTPCacheTaskKeysRequest) (*pb.ValidateHTTPCacheTaskKeysResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx *dbs.Tx
// 检查Key数量
var clusterId int64
if userId > 0 {
clusterId, err = models.SharedUserDAO.FindUserClusterId(tx, userId)
if err != nil {
return nil, err
}
}
var pbFailResults = []*pb.ValidateHTTPCacheTaskKeysResponse_FailKey{}
var domainMap = map[string]*models.Server{} // domain name => *Server
for _, key := range req.Keys {
if len(key) == 0 {
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
Key: key,
ReasonCode: "requireKey",
})
continue
}
// 获取域名
var domain = utils.ParseDomainFromKey(key)
if len(domain) == 0 {
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
Key: key,
ReasonCode: "requireDomain",
})
continue
}
// 查询所在集群
server, ok := domainMap[domain]
if !ok {
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
if err != nil {
return nil, err
}
if server == nil {
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
Key: key,
ReasonCode: "requireServer",
})
continue
}
domainMap[domain] = server
}
// 检查用户
if userId > 0 {
if int64(server.UserId) != userId {
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
Key: key,
ReasonCode: "requireUser",
})
continue
}
}
var serverClusterId = int64(server.ClusterId)
if serverClusterId == 0 {
if clusterId > 0 {
serverClusterId = clusterId
} else {
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
Key: key,
ReasonCode: "requireClusterId",
})
continue
}
}
}
return &pb.ValidateHTTPCacheTaskKeysResponse{FailKeys: pbFailResults}, nil
}
// FindDoingHTTPCacheTaskKeys 查找需要执行的Key
func (this *HTTPCacheTaskKeyService) FindDoingHTTPCacheTaskKeys(ctx context.Context, req *pb.FindDoingHTTPCacheTaskKeysRequest) (*pb.FindDoingHTTPCacheTaskKeysResponse, error) {
nodeId, err := this.ValidateNode(ctx)
if err != nil {
return nil, err
}
if req.Size <= 0 {
req.Size = 100
}
var tx *dbs.Tx
keys, err := models.SharedHTTPCacheTaskKeyDAO.FindDoingTaskKeys(tx, nodeId, req.Size)
if err != nil {
return nil, err
}
var pbKeys = []*pb.HTTPCacheTaskKey{}
for _, key := range keys {
pbKeys = append(pbKeys, &pb.HTTPCacheTaskKey{
Id: int64(key.Id),
TaskId: int64(key.TaskId),
Key: key.Key,
Type: key.Type,
KeyType: key.KeyType,
NodeClusterId: int64(key.ClusterId),
})
}
return &pb.FindDoingHTTPCacheTaskKeysResponse{HttpCacheTaskKeys: pbKeys}, nil
}
// UpdateHTTPCacheTaskKeysStatus 更新一组Key状态
func (this *HTTPCacheTaskKeyService) UpdateHTTPCacheTaskKeysStatus(ctx context.Context, req *pb.UpdateHTTPCacheTaskKeysStatusRequest) (*pb.RPCSuccess, error) {
nodeId, err := this.ValidateNode(ctx)
if err != nil {
return nil, err
}
var tx *dbs.Tx
var nodesJSONMap = map[int64][]byte{} // clusterId => nodesJSON
for _, result := range req.KeyResults {
// 集群Id
var clusterId = result.NodeClusterId
nodesJSON, ok := nodesJSONMap[clusterId]
if !ok {
nodeIdsInCluster, err := models.SharedNodeDAO.FindEnabledAndOnNodeIdsWithClusterId(tx, clusterId, true)
if err != nil {
return nil, err
}
var nodeMap = map[int64]bool{}
for _, nodeIdInCluster := range nodeIdsInCluster {
nodeMap[nodeIdInCluster] = true
}
nodesJSON, err = json.Marshal(nodeMap)
if err != nil {
return nil, err
}
nodesJSONMap[clusterId] = nodesJSON
}
err = models.SharedHTTPCacheTaskKeyDAO.UpdateKeyStatus(tx, result.Id, nodeId, result.Error, nodesJSON)
if err != nil {
return nil, err
}
}
return this.Success()
}

View File

@@ -0,0 +1,23 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package services
import (
"github.com/iwind/TeaGo/assert"
"testing"
)
func TestHTTPCacheTaskService_CountHTTPCacheTasks(t *testing.T) {
var a = assert.NewAssertion(t)
var service = &HTTPCacheTaskService{}
a.IsTrue(service.parseDomain("aaa") == "aaa")
a.IsTrue(service.parseDomain("AAA") == "aaa")
a.IsTrue(service.parseDomain("a.b-c.com") == "a.b-c.com")
a.IsTrue(service.parseDomain("a.b-c.com/hello/world") == "a.b-c.com")
a.IsTrue(service.parseDomain("https://a.b-c.com") == "a.b-c.com")
a.IsTrue(service.parseDomain("http://a.b-c.com/hello/world") == "a.b-c.com")
a.IsTrue(service.parseDomain("http://a.B-c.com/hello/world") == "a.b-c.com")
a.IsTrue(service.parseDomain("http:/aaaa.com") == "http")
a.IsTrue(service.parseDomain("北京") == "")
}

View File

@@ -173,7 +173,7 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
return nil, err return nil, err
} }
templatePolicy := firewallconfigs.HTTPFirewallTemplate() var templatePolicy = firewallconfigs.HTTPFirewallTemplate()
tx := this.NullTx() tx := this.NullTx()
@@ -186,18 +186,18 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
return nil, errors.New("can not found firewall policy") return nil, errors.New("can not found firewall policy")
} }
inboundConfig := firewallPolicy.Inbound var inboundConfig = firewallPolicy.Inbound
if inboundConfig == nil { if inboundConfig == nil {
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true} inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
} }
outboundConfig := firewallPolicy.Outbound var outboundConfig = firewallPolicy.Outbound
if outboundConfig == nil { if outboundConfig == nil {
outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true} outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
} }
// 更新老的 // 更新老的
oldCodes := []string{} var oldCodes = []string{}
if firewallPolicy.Inbound != nil { if firewallPolicy.Inbound != nil {
for _, g := range firewallPolicy.Inbound.Groups { for _, g := range firewallPolicy.Inbound.Groups {
if len(g.Code) > 0 { if len(g.Code) > 0 {
@@ -301,7 +301,7 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
} }
} }
err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig) err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.CaptchaOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -0,0 +1,20 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
// +build !plus
package services
import (
"context"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UpdateHTTPWebUAM 修改UAM设置
func (this *HTTPWebService) UpdateHTTPWebUAM(ctx context.Context, req *pb.UpdateHTTPWebUAMRequest) (*pb.RPCSuccess, error) {
return this.Success()
}
// FindHTTPWebUAM 查找UAM设置
func (this *HTTPWebService) FindHTTPWebUAM(ctx context.Context, req *pb.FindHTTPWebUAMRequest) (*pb.FindHTTPWebUAMResponse, error) {
return &pb.FindHTTPWebUAMResponse{UamJSON: nil}, nil
}

View File

@@ -114,23 +114,42 @@ func (this *IPItemService) DeleteIPItem(ctx context.Context, req *pb.DeleteIPIte
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
if userId > 0 { // 如果是使用IPItemId删除
listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId) if req.IpItemId > 0 {
if err != nil { if userId > 0 {
return nil, err listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId)
if err != nil {
return nil, err
}
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, listId)
if err != nil {
return nil, err
}
} }
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, listId) err = models.SharedIPItemDAO.DisableIPItem(tx, req.IpItemId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
err = models.SharedIPItemDAO.DisableIPItem(tx, req.IpItemId) // 如果是使用ipFrom+ipTo删除
if err != nil { if len(req.IpFrom) > 0 {
return nil, err // 检查IP列表
if req.IpListId > 0 && userId > 0 {
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, req.IpListId)
if err != nil {
return nil, err
}
}
err = models.SharedIPItemDAO.DisableIPItemsWithIP(tx, req.IpFrom, req.IpTo, userId, req.IpListId)
if err != nil {
return nil, err
}
} }
return this.Success() return this.Success()

View File

@@ -21,9 +21,20 @@ func (this *IPListService) CreateIPList(ctx context.Context, req *pb.CreateIPLis
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
listId, err := models.SharedIPListDAO.CreateIPList(tx, userId, req.Type, req.Name, req.Code, req.TimeoutJSON, req.Description, req.IsPublic, req.IsGlobal) // 检查用户相关信息
if userId > 0 {
// 检查服务ID
if req.ServerId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
if err != nil {
return nil, err
}
}
}
listId, err := models.SharedIPListDAO.CreateIPList(tx, userId, req.ServerId, req.Type, req.Name, req.Code, req.TimeoutJSON, req.Description, req.IsPublic, req.IsGlobal)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,12 +61,18 @@ func (this *IPListService) UpdateIPList(ctx context.Context, req *pb.UpdateIPLis
// FindEnabledIPList 查找IP列表 // FindEnabledIPList 查找IP列表
func (this *IPListService) FindEnabledIPList(ctx context.Context, req *pb.FindEnabledIPListRequest) (*pb.FindEnabledIPListResponse, error) { func (this *IPListService) FindEnabledIPList(ctx context.Context, req *pb.FindEnabledIPListRequest) (*pb.FindEnabledIPListResponse, error) {
// 校验请求 // 校验请求
_, err := this.ValidateAdmin(ctx, 0) _, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
if userId > 0 {
err = models.SharedIPListDAO.CheckUserIPList(tx, userId, req.IpListId)
if err != nil {
return nil, err
}
}
list, err := models.SharedIPListDAO.FindEnabledIPList(tx, req.IpListId, nil) list, err := models.SharedIPListDAO.FindEnabledIPList(tx, req.IpListId, nil)
if err != nil { if err != nil {

View File

@@ -5,10 +5,81 @@ package services
import ( import (
"context" "context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"strings"
"sync"
"time"
) )
// 队列相关数据
var metricStatsMap = map[string]*pb.UploadMetricStatsRequest{} // key (clusterId@nodeId@serverId@itemId) => UploadMetricStatsRequest
var metricStatKeysQueue = make(chan string, 100_000)
var metricStatsLocker = &sync.Mutex{}
func init() {
dbs.OnReadyDone(func() {
goman.New(func() {
// 将队列导入数据库
var countKeys = 0
for key := range metricStatKeysQueue {
err := func(key string) error {
var tx *dbs.Tx
metricStatsLocker.Lock()
req, ok := metricStatsMap[key]
if !ok {
metricStatsLocker.Unlock()
return nil
}
delete(metricStatsMap, key)
metricStatsLocker.Unlock()
var pieces = strings.Split(key, "@")
var clusterId = types.Int64(pieces[0])
var nodeId = types.Int64(pieces[1])
var serverId = types.Int64(pieces[2])
var itemId = types.Int64(pieces[3])
// 删除旧的数据
err := models.SharedMetricStatDAO.DeleteNodeItemStats(tx, nodeId, serverId, itemId, req.Time)
if err != nil {
return err
}
for _, stat := range req.MetricStats {
err := models.SharedMetricStatDAO.CreateStat(tx, stat.Hash, clusterId, nodeId, req.ServerId, req.ItemId, stat.Keys, float64(stat.Value), req.Time, req.Version)
if err != nil {
return err
}
}
// 保存总和
err = models.SharedMetricSumStatDAO.UpdateSum(tx, clusterId, nodeId, req.ServerId, req.Time, req.ItemId, req.Version, req.Count, req.Total)
if err != nil {
return err
}
return nil
}(key)
if err != nil {
remotelogs.Error("METRIC_STAT", "upload metric stats failed: "+err.Error())
}
// 人为限速
countKeys++
if countKeys >= 100 {
countKeys = 0
time.Sleep(1 * time.Second)
}
}
})
})
}
// MetricStatService 指标统计数据相关服务 // MetricStatService 指标统计数据相关服务
type MetricStatService struct { type MetricStatService struct {
BaseService BaseService
@@ -27,24 +98,18 @@ func (this *MetricStatService) UploadMetricStats(ctx context.Context, req *pb.Up
return nil, err return nil, err
} }
// 删除旧的数据 var key = types.String(clusterId) + "@" + types.String(nodeId) + "@" + types.String(req.ServerId) + "@" + types.String(req.ItemId)
err = models.SharedMetricStatDAO.DeleteNodeItemStats(tx, nodeId, req.ServerId, req.ItemId, req.Time) metricStatsLocker.Lock()
if err != nil { metricStatsMap[key] = req
return nil, err
select {
case metricStatKeysQueue <- key:
default:
// 如果满了就删除
delete(metricStatsMap, key)
} }
for _, stat := range req.MetricStats { metricStatsLocker.Unlock()
err := models.SharedMetricStatDAO.CreateStat(tx, stat.Hash, clusterId, nodeId, req.ServerId, req.ItemId, stat.Keys, float64(stat.Value), req.Time, req.Version)
if err != nil {
return nil, err
}
}
// 保存总和
err = models.SharedMetricSumStatDAO.UpdateSum(tx, clusterId, nodeId, req.ServerId, req.Time, req.ItemId, req.Version, req.Count, req.Total)
if err != nil {
return nil, err
}
return this.Success() return this.Success()
} }

View File

@@ -10,17 +10,18 @@ import (
"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/installers" "github.com/TeaOSLab/EdgeAPI/internal/installers"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/andybalholm/brotli" "github.com/andybalholm/brotli"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string" stringutil "github.com/iwind/TeaGo/utils/string"
"io" "io"
@@ -399,7 +400,7 @@ func (this *NodeService) FindAllEnabledNodesWithNodeClusterId(ctx context.Contex
tx := this.NullTx() tx := this.NullTx()
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId) nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId, req.IncludeSecondary)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -767,13 +768,14 @@ func (this *NodeService) FindCurrentNodeConfig(ctx context.Context, req *pb.Find
NodeJSON: data, NodeJSON: data,
DataSize: int64(len(data)), DataSize: int64(len(data)),
IsCompressed: isCompressed, IsCompressed: isCompressed,
Timestamp: time.Now().Unix(),
}, nil }, nil
} }
// UpdateNodeStatus 更新节点状态 // UpdateNodeStatus 更新节点状态
func (this *NodeService) UpdateNodeStatus(ctx context.Context, req *pb.UpdateNodeStatusRequest) (*pb.RPCSuccess, error) { func (this *NodeService) UpdateNodeStatus(ctx context.Context, req *pb.UpdateNodeStatusRequest) (*pb.RPCSuccess, error) {
// 校验节点 // 校验节点
_, _, nodeId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode) nodeId, err := this.ValidateNode(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -786,9 +788,18 @@ func (this *NodeService) UpdateNodeStatus(ctx context.Context, req *pb.UpdateNod
return nil, errors.New("'nodeId' should be greater than 0") return nil, errors.New("'nodeId' should be greater than 0")
} }
tx := this.NullTx() var tx = this.NullTx()
err = models.SharedNodeDAO.UpdateNodeStatus(tx, nodeId, req.StatusJSON) // 修改时间戳
var nodeStatus = &nodeconfigs.NodeStatus{}
err = json.Unmarshal(req.StatusJSON, nodeStatus)
if err != nil {
return nil, errors.New("decode node status json failed: " + err.Error())
}
nodeStatus.UpdatedAt = time.Now().Unix()
// 保存
err = models.SharedNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -823,7 +834,7 @@ func (this *NodeService) InstallNode(ctx context.Context, req *pb.InstallNodeReq
goman.New(func() { goman.New(func() {
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, false) err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, false)
if err != nil { if err != nil {
logs.Println("[RPC]install node:" + err.Error()) remotelogs.Error("NODE_SERVICE", "install node failed:"+err.Error())
} }
}) })
@@ -863,7 +874,7 @@ func (this *NodeService) UpgradeNode(ctx context.Context, req *pb.UpgradeNodeReq
goman.New(func() { goman.New(func() {
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, true) err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, true)
if err != nil { if err != nil {
logs.Println("[RPC]install node:" + err.Error()) remotelogs.Error("NODE_SERVICE", "install node:"+err.Error())
} }
}) })
@@ -1591,12 +1602,12 @@ func (this *NodeService) UpdateNodeUp(ctx context.Context, req *pb.UpdateNodeUpR
// DownloadNodeInstallationFile 下载最新边缘节点安装文件 // DownloadNodeInstallationFile 下载最新边缘节点安装文件
func (this *NodeService) DownloadNodeInstallationFile(ctx context.Context, req *pb.DownloadNodeInstallationFileRequest) (*pb.DownloadNodeInstallationFileResponse, error) { func (this *NodeService) DownloadNodeInstallationFile(ctx context.Context, req *pb.DownloadNodeInstallationFileRequest) (*pb.DownloadNodeInstallationFileResponse, error) {
_, err := this.ValidateNode(ctx) nodeId, err := this.ValidateNode(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
file := installers.SharedDeployManager.FindNodeFile(req.Os, req.Arch) var file = installers.SharedDeployManager.FindNodeFile(req.Os, req.Arch)
if file == nil { if file == nil {
return &pb.DownloadNodeInstallationFileResponse{}, nil return &pb.DownloadNodeInstallationFileResponse{}, nil
} }
@@ -1611,6 +1622,9 @@ func (this *NodeService) DownloadNodeInstallationFile(ctx context.Context, req *
return nil, err return nil, err
} }
// 增加下载速度监控
installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleNode, nodeId, int64(len(data)))
return &pb.DownloadNodeInstallationFileResponse{ return &pb.DownloadNodeInstallationFileResponse{
Sum: sum, Sum: sum,
Offset: offset, Offset: offset,
@@ -1746,3 +1760,204 @@ func (this *NodeService) FindNodeLevelInfo(ctx context.Context, req *pb.FindNode
return result, nil return result, nil
} }
// FindNodeDNSResolver 读取节点DNS Resolver
func (this *NodeService) FindNodeDNSResolver(ctx context.Context, req *pb.FindNodeDNSResolverRequest) (*pb.FindNodeDNSResolverResponse, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
config, err := models.SharedNodeDAO.FindNodeDNSResolver(tx, req.NodeId)
if err != nil {
return nil, err
}
configJSON, err := json.Marshal(config)
if err != nil {
return nil, err
}
return &pb.FindNodeDNSResolverResponse{
DnsResolverJSON: configJSON,
}, nil
}
// UpdateNodeDNSResolver 修改DNS Resolver
func (this *NodeService) UpdateNodeDNSResolver(ctx context.Context, req *pb.UpdateNodeDNSResolverRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var config = nodeconfigs.DefaultDNSResolverConfig()
err = json.Unmarshal(req.DnsResolverJSON, config)
if err != nil {
return nil, err
}
err = models.SharedNodeDAO.UpdateNodeDNSResolver(tx, req.NodeId, config)
if err != nil {
return nil, err
}
return this.Success()
}
// FindNodeDDoSProtection 获取集群的DDoS设置
func (this *NodeService) FindNodeDDoSProtection(ctx context.Context, req *pb.FindNodeDDoSProtectionRequest) (*pb.FindNodeDDoSProtectionResponse, error) {
var nodeId = req.NodeId
var isFromNode = false
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
// 检查是否来自节点
currentNodeId, err2 := this.ValidateNode(ctx)
if err2 != nil {
return nil, err
}
if nodeId > 0 && currentNodeId != nodeId {
return nil, errors.New("invalid 'nodeId'")
}
nodeId = currentNodeId
isFromNode = true
}
var tx *dbs.Tx
ddosProtection, err := models.SharedNodeDAO.FindNodeDDoSProtection(tx, nodeId)
if err != nil {
return nil, err
}
if ddosProtection == nil {
ddosProtection = ddosconfigs.DefaultProtectionConfig()
}
// 组合父级节点配置
// 只有从节点读取配置时才需要组合
if isFromNode {
clusterId, err := models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
if err != nil {
return nil, err
}
if clusterId > 0 {
clusterDDoSProtection, err := models.SharedNodeClusterDAO.FindClusterDDoSProtection(tx, clusterId)
if err != nil {
return nil, err
}
if clusterDDoSProtection == nil {
clusterDDoSProtection = ddosconfigs.DefaultProtectionConfig()
}
clusterDDoSProtection.Merge(ddosProtection)
ddosProtection = clusterDDoSProtection
}
}
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return nil, err
}
var result = &pb.FindNodeDDoSProtectionResponse{
DdosProtectionJSON: ddosProtectionJSON,
}
return result, nil
}
// UpdateNodeDDoSProtection 修改集群的DDOS设置
func (this *NodeService) UpdateNodeDDoSProtection(ctx context.Context, req *pb.UpdateNodeDDoSProtectionRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var ddosProtection = &ddosconfigs.ProtectionConfig{}
err = json.Unmarshal(req.DdosProtectionJSON, ddosProtection)
if err != nil {
return nil, err
}
var tx *dbs.Tx
err = models.SharedNodeDAO.UpdateNodeDDoSProtection(tx, req.NodeId, ddosProtection)
if err != nil {
return nil, err
}
return this.Success()
}
// FindEnabledNodeConfigInfo 取得节点的配置概要信息
func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.FindEnabledNodeConfigInfoRequest) (*pb.FindEnabledNodeConfigInfoResponse, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var result = &pb.FindEnabledNodeConfigInfoResponse{}
node, err := models.SharedNodeDAO.FindEnabledNode(tx, req.NodeId)
if err != nil {
return nil, err
}
if node == nil {
// 总是返回非空
return result, nil
}
// dns
if len(node.DNSRouteCodes()) > 0 {
result.HasDNSInfo = true
}
// cache
if len(node.CacheDiskDir) > 0 {
result.HasCacheInfo = true
} else {
var diskCapacity = node.DecodeMaxCacheDiskCapacity()
var memoryCapacity = node.DecodeMaxCacheMemoryCapacity()
if (diskCapacity != nil && diskCapacity.IsNotEmpty()) || (memoryCapacity != nil && memoryCapacity.IsNotEmpty()) {
result.HasCacheInfo = true
}
}
// thresholds
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, 0, req.NodeId)
if err != nil {
return nil, err
}
result.HasThresholds = countThresholds > 0
// ssh
nodeLogin, err := models.SharedNodeLoginDAO.FindEnabledNodeLoginWithNodeId(tx, nodeconfigs.NodeRoleNode, req.NodeId)
if err != nil {
return nil, err
}
if nodeLogin != nil {
sshParams, err := nodeLogin.DecodeSSHParams()
if err != nil {
return nil, err
}
if sshParams != nil {
result.HasSSH = len(sshParams.Host) > 0 || sshParams.Port > 0
}
}
// systemSettings
if node.MaxCPU > 0 {
result.HasSystemSettings = true
} else {
// dns resolver
var dnsResolverConfig = node.DecodeDNSResolver()
if dnsResolverConfig != nil {
result.HasSystemSettings = dnsResolverConfig.Type != nodeconfigs.DNSResolverTypeDefault
}
}
// ddos protection
result.HasDDoSProtection = node.HasDDoSProtection()
return result, nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -83,7 +84,7 @@ func (this *NodeClusterService) UpdateNodeCluster(ctx context.Context, req *pb.U
tx := this.NullTx() tx := this.NullTx()
err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.NodeTCPMaxConnections, req.AutoOpenPorts) err = models.SharedNodeClusterDAO.UpdateCluster(tx, req.NodeClusterId, req.Name, req.NodeGrantId, req.InstallDir, req.TimeZone, req.NodeMaxThreads, req.AutoOpenPorts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -148,22 +149,21 @@ func (this *NodeClusterService) FindEnabledNodeCluster(ctx context.Context, req
} }
return &pb.FindEnabledNodeClusterResponse{NodeCluster: &pb.NodeCluster{ return &pb.FindEnabledNodeClusterResponse{NodeCluster: &pb.NodeCluster{
Id: int64(cluster.Id), Id: int64(cluster.Id),
Name: cluster.Name, Name: cluster.Name,
CreatedAt: int64(cluster.CreatedAt), CreatedAt: int64(cluster.CreatedAt),
InstallDir: cluster.InstallDir, InstallDir: cluster.InstallDir,
NodeGrantId: int64(cluster.GrantId), NodeGrantId: int64(cluster.GrantId),
UniqueId: cluster.UniqueId, UniqueId: cluster.UniqueId,
Secret: cluster.Secret, Secret: cluster.Secret,
HttpCachePolicyId: int64(cluster.CachePolicyId), HttpCachePolicyId: int64(cluster.CachePolicyId),
HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId), HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId),
DnsName: cluster.DnsName, DnsName: cluster.DnsName,
DnsDomainId: int64(cluster.DnsDomainId), DnsDomainId: int64(cluster.DnsDomainId),
IsOn: cluster.IsOn, IsOn: cluster.IsOn,
TimeZone: cluster.TimeZone, TimeZone: cluster.TimeZone,
NodeMaxThreads: int32(cluster.NodeMaxThreads), NodeMaxThreads: int32(cluster.NodeMaxThreads),
NodeTCPMaxConnections: int32(cluster.NodeTCPMaxConnections), AutoOpenPorts: cluster.AutoOpenPorts == 1,
AutoOpenPorts: cluster.AutoOpenPorts == 1,
}}, nil }}, nil
} }
@@ -429,7 +429,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
dnsInfo, err := models.SharedNodeClusterDAO.FindClusterDNSInfo(tx, req.NodeClusterId, nil) dnsInfo, err := models.SharedNodeClusterDAO.FindClusterDNSInfo(tx, req.NodeClusterId, nil)
if err != nil { if err != nil {
@@ -457,6 +457,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
ServersAutoSync: dnsConfig.ServersAutoSync, ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords, CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL, Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
}, nil }, nil
} }
@@ -471,7 +472,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
Provider: nil, Provider: nil,
}, nil }, nil
} }
pbDomain := &pb.DNSDomain{ var pbDomain = &pb.DNSDomain{
Id: int64(domain.Id), Id: int64(domain.Id),
Name: domain.Name, Name: domain.Name,
IsOn: domain.IsOn, IsOn: domain.IsOn,
@@ -515,6 +516,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
ServersAutoSync: dnsConfig.ServersAutoSync, ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords, CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL, Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
DefaultRoute: defaultRoute, DefaultRoute: defaultRoute,
}, nil }, nil
} }
@@ -527,7 +529,7 @@ func (this *NodeClusterService) CountAllEnabledNodeClustersWithDNSProviderId(ctx
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSProviderId(tx, req.DnsProviderId) count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSProviderId(tx, req.DnsProviderId)
if err != nil { if err != nil {
@@ -544,7 +546,7 @@ func (this *NodeClusterService) CountAllEnabledNodeClustersWithDNSDomainId(ctx c
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId) count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId)
if err != nil { if err != nil {
@@ -561,7 +563,7 @@ func (this *NodeClusterService) FindAllEnabledNodeClustersWithDNSDomainId(ctx co
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId) clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId)
if err != nil { if err != nil {
@@ -589,7 +591,7 @@ func (this *NodeClusterService) CheckNodeClusterDNSName(ctx context.Context, req
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
exists, err := models.SharedNodeClusterDAO.ExistClusterDNSName(tx, req.DnsName, req.NodeClusterId) exists, err := models.SharedNodeClusterDAO.ExistClusterDNSName(tx, req.DnsName, req.NodeClusterId)
if err != nil { if err != nil {
@@ -606,9 +608,9 @@ func (this *NodeClusterService) UpdateNodeClusterDNS(ctx context.Context, req *p
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
err = models.SharedNodeClusterDAO.UpdateClusterDNS(tx, req.NodeClusterId, req.DnsName, req.DnsDomainId, req.NodesAutoSync, req.ServersAutoSync, req.CnameRecords, req.Ttl) err = models.SharedNodeClusterDAO.UpdateClusterDNS(tx, req.NodeClusterId, req.DnsName, req.DnsDomainId, req.NodesAutoSync, req.ServersAutoSync, req.CnameRecords, req.Ttl, req.CnameAsDomain)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1040,6 +1042,18 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
result.WebpIsOn = nodeconfigs.DefaultWebPImagePolicy.IsOn result.WebpIsOn = nodeconfigs.DefaultWebPImagePolicy.IsOn
} }
// UAM
if models.IsNotNull(cluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(cluster.Uam, uamPolicy)
if err != nil {
return nil, err
}
result.UamIsOn = uamPolicy.IsOn
} else {
result.UamIsOn = nodeconfigs.DefaultUAMPolicy.IsOn
}
// system service // system service
if models.IsNotNull(cluster.SystemServices) { if models.IsNotNull(cluster.SystemServices) {
var servicesMap = map[string]maps.Map{} var servicesMap = map[string]maps.Map{}
@@ -1054,6 +1068,9 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
} }
} }
// ddos
result.HasDDoSProtection = cluster.HasDDoSProtection()
return result, nil return result, nil
} }
@@ -1101,16 +1118,116 @@ func (this *NodeClusterService) UpdateNodeClusterWebPPolicy(ctx context.Context,
return nil, err return nil, err
} }
var tx = this.NullTx()
var webpPolicy = &nodeconfigs.WebPImagePolicy{} var webpPolicy = &nodeconfigs.WebPImagePolicy{}
err = json.Unmarshal(req.WebpPolicyJSON, webpPolicy) err = json.Unmarshal(req.WebpPolicyJSON, webpPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = webpPolicy.Init()
if err != nil {
return nil, errors.New("validate webp policy failed: " + err.Error())
}
var tx = this.NullTx()
err = models.SharedNodeClusterDAO.UpdateClusterWebPPolicy(tx, req.NodeClusterId, webpPolicy) err = models.SharedNodeClusterDAO.UpdateClusterWebPPolicy(tx, req.NodeClusterId, webpPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return this.Success() return this.Success()
} }
// FindEnabledNodeClusterUAMPolicy 读取集群UAM策略
func (this *NodeClusterService) FindEnabledNodeClusterUAMPolicy(ctx context.Context, req *pb.FindEnabledNodeClusterUAMPolicyRequest) (*pb.FindEnabledNodeClusterUAMPolicyResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
uamPolicy, err := models.SharedNodeClusterDAO.FindClusterUAMPolicy(tx, req.NodeClusterId, nil)
if err != nil {
return nil, err
}
uamPolicyJSON, err := json.Marshal(uamPolicy)
if err != nil {
return nil, err
}
return &pb.FindEnabledNodeClusterUAMPolicyResponse{
UamPolicyJSON: uamPolicyJSON,
}, nil
}
// UpdateNodeClusterUAMPolicy 设置集群的UAM策略
func (this *NodeClusterService) UpdateNodeClusterUAMPolicy(ctx context.Context, req *pb.UpdateNodeClusterUAMPolicyRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var uamPolicy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(req.UamPolicyJSON, uamPolicy)
if err != nil {
return nil, err
}
err = uamPolicy.Init()
if err != nil {
return nil, errors.New("validate uam policy failed: " + err.Error())
}
var tx = this.NullTx()
err = models.SharedNodeClusterDAO.UpdateClusterUAMPolicy(tx, req.NodeClusterId, uamPolicy)
if err != nil {
return nil, err
}
return this.Success()
}
// FindNodeClusterDDoSProtection 获取集群的DDOS设置
func (this *NodeClusterService) FindNodeClusterDDoSProtection(ctx context.Context, req *pb.FindNodeClusterDDoSProtectionRequest) (*pb.FindNodeClusterDDoSProtectionResponse, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var tx *dbs.Tx
ddosProtection, err := models.SharedNodeClusterDAO.FindClusterDDoSProtection(tx, req.NodeClusterId)
if err != nil {
return nil, err
}
if ddosProtection == nil {
ddosProtection = ddosconfigs.DefaultProtectionConfig()
}
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return nil, err
}
var result = &pb.FindNodeClusterDDoSProtectionResponse{
DdosProtectionJSON: ddosProtectionJSON,
}
return result, nil
}
// UpdateNodeClusterDDoSProtection 修改集群的DDOS设置
func (this *NodeClusterService) UpdateNodeClusterDDoSProtection(ctx context.Context, req *pb.UpdateNodeClusterDDoSProtectionRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx, 0)
if err != nil {
return nil, err
}
var ddosProtection = &ddosconfigs.ProtectionConfig{}
err = json.Unmarshal(req.DdosProtectionJSON, ddosProtection)
if err != nil {
return nil, err
}
var tx *dbs.Tx
err = models.SharedNodeClusterDAO.UpdateClusterDDoSProtection(tx, req.NodeClusterId, ddosProtection)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -32,7 +32,7 @@ func (this *NodeTaskService) FindNodeTasks(ctx context.Context, req *pb.FindNode
return nil, err return nil, err
} }
pbTasks := []*pb.NodeTask{} var pbTasks = []*pb.NodeTask{}
for _, task := range tasks { for _, task := range tasks {
pbTasks = append(pbTasks, &pb.NodeTask{ pbTasks = append(pbTasks, &pb.NodeTask{
Id: int64(task.Id), Id: int64(task.Id),
@@ -44,13 +44,13 @@ func (this *NodeTaskService) FindNodeTasks(ctx context.Context, req *pb.FindNode
} }
// 边缘节点版本更新任务 // 边缘节点版本更新任务
if nodeType == rpcutils.UserTypeNode { if nodeType == rpcutils.UserTypeNode && installers.SharedUpgradeLimiter.CanUpgrade() {
status, err := models.SharedNodeDAO.FindNodeStatus(tx, nodeId) status, err := models.SharedNodeDAO.FindNodeStatus(tx, nodeId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if status != nil && len(status.OS) > 0 && len(status.Arch) > 0 && len(status.BuildVersion) > 0 { if status != nil && len(status.OS) > 0 && len(status.Arch) > 0 && len(status.BuildVersion) > 0 {
deployFile := installers.SharedDeployManager.FindNodeFile(status.OS, status.Arch) var deployFile = installers.SharedDeployManager.FindNodeFile(status.OS, status.Arch)
if deployFile != nil { if deployFile != nil {
if stringutil.VersionCompare(deployFile.Version, status.BuildVersion) > 0 { if stringutil.VersionCompare(deployFile.Version, status.BuildVersion) > 0 {
pbTasks = append(pbTasks, &pb.NodeTask{ pbTasks = append(pbTasks, &pb.NodeTask{

View File

@@ -72,7 +72,7 @@ func (this *OriginService) CreateOrigin(ctx context.Context, req *pb.CreateOrigi
} }
} }
originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, userId, req.Name, string(addrMap.AsJSON()), req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host) originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, userId, req.Name, string(addrMap.AsJSON()), req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -87,20 +87,23 @@ func (this *OriginService) UpdateOrigin(ctx context.Context, req *pb.UpdateOrigi
return nil, err return nil, err
} }
var tx = this.NullTx()
if userId > 0 { if userId > 0 {
// TODO 校验权限 err = models.SharedOriginDAO.CheckUserOrigin(tx, userId, req.OriginId)
if err != nil {
return nil, err
}
} }
if req.Addr == nil { if req.Addr == nil {
return nil, errors.New("'addr' can not be nil") return nil, errors.New("'addr' can not be nil")
} }
addrMap := maps.Map{ var addrMap = maps.Map{
"protocol": req.Addr.Protocol, "protocol": req.Addr.Protocol,
"portRange": req.Addr.PortRange, "portRange": req.Addr.PortRange,
"host": req.Addr.Host, "host": req.Addr.Host,
} }
tx := this.NullTx()
// 校验参数 // 校验参数
var connTimeout = &shared.TimeDuration{} var connTimeout = &shared.TimeDuration{}
if len(req.ConnTimeoutJSON) > 0 { if len(req.ConnTimeoutJSON) > 0 {
@@ -139,7 +142,7 @@ func (this *OriginService) UpdateOrigin(ctx context.Context, req *pb.UpdateOrigi
} }
} }
err = models.SharedOriginDAO.UpdateOrigin(tx, req.OriginId, req.Name, string(addrMap.AsJSON()), req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host) err = models.SharedOriginDAO.UpdateOrigin(tx, req.OriginId, req.Name, string(addrMap.AsJSON()), req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -154,11 +157,14 @@ func (this *OriginService) FindEnabledOrigin(ctx context.Context, req *pb.FindEn
return nil, err return nil, err
} }
if userId > 0 { var tx = this.NullTx()
// TODO 校验权限
}
tx := this.NullTx() if userId > 0 {
err = models.SharedOriginDAO.CheckUserOrigin(tx, userId, req.OriginId)
if err != nil {
return nil, err
}
}
origin, err := models.SharedOriginDAO.FindEnabledOrigin(tx, req.OriginId) origin, err := models.SharedOriginDAO.FindEnabledOrigin(tx, req.OriginId)
if err != nil { if err != nil {
@@ -196,11 +202,14 @@ func (this *OriginService) FindEnabledOriginConfig(ctx context.Context, req *pb.
return nil, err return nil, err
} }
if userId > 0 { var tx = this.NullTx()
// TODO 校验权限
}
tx := this.NullTx() if userId > 0 {
err = models.SharedOriginDAO.CheckUserOrigin(tx, userId, req.OriginId)
if err != nil {
return nil, err
}
}
config, err := models.SharedOriginDAO.ComposeOriginConfig(tx, req.OriginId, nil) config, err := models.SharedOriginDAO.ComposeOriginConfig(tx, req.OriginId, nil)
if err != nil { if err != nil {

View File

@@ -27,12 +27,39 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
} }
var pbCities = []*pb.RegionCity{} var pbCities = []*pb.RegionCity{}
var provincesMap = map[int64]*regions.RegionProvince{} // provinceId => RegionProvince
for _, city := range cities { for _, city := range cities {
var provinceId = int64(city.ProvinceId)
var pbProvince = &pb.RegionProvince{Id: provinceId}
if req.IncludeRegionProvince {
province, ok := provincesMap[provinceId]
if !ok {
province, err = regions.SharedRegionProvinceDAO.FindEnabledRegionProvince(tx, provinceId)
if err != nil {
return nil, err
}
if province == nil {
continue
}
provincesMap[provinceId] = province
}
pbProvince = &pb.RegionProvince{
Id: int64(province.Id),
Name: province.Name,
Codes: province.DecodeCodes(),
}
}
pbCities = append(pbCities, &pb.RegionCity{ pbCities = append(pbCities, &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.Id),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),
RegionProvince: pbProvince,
}) })
} }

View File

@@ -84,7 +84,7 @@ func (this *ReverseProxyService) FindEnabledReverseProxyConfig(ctx context.Conte
} }
} }
tx := this.NullTx() var tx = this.NullTx()
config, err := models.SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, req.ReverseProxyId, nil) config, err := models.SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, req.ReverseProxyId, nil)
if err != nil { if err != nil {
@@ -189,7 +189,7 @@ func (this *ReverseProxyService) UpdateReverseProxy(ctx context.Context, req *pb
} }
} }
tx := this.NullTx() var tx = this.NullTx()
// 校验参数 // 校验参数
var connTimeout = &shared.TimeDuration{} var connTimeout = &shared.TimeDuration{}
@@ -216,7 +216,7 @@ func (this *ReverseProxyService) UpdateReverseProxy(ctx context.Context, req *pb
} }
} }
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects) err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -9,7 +9,6 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns" "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions" "github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
"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/lists" "github.com/iwind/TeaGo/lists"
@@ -154,7 +153,7 @@ func (this *ServerService) CreateServer(ctx context.Context, req *pb.CreateServe
} }
} }
serverId, err := models.SharedServerDAO.CreateServer(tx, req.AdminId, req.UserId, req.Type, req.Name, req.Description, serverNamesJSON, isAuditing, auditingServerNamesJSON, req.HttpJSON, req.HttpsJSON, req.TcpJSON, req.TlsJSON, req.UnixJSON, req.UdpJSON, req.WebId, req.ReverseProxyJSON, req.NodeClusterId, string(req.IncludeNodesJSON), string(req.ExcludeNodesJSON), req.ServerGroupIds, req.UserPlanId) serverId, err := models.SharedServerDAO.CreateServer(tx, req.AdminId, req.UserId, req.Type, req.Name, req.Description, serverNamesJSON, isAuditing, auditingServerNamesJSON, req.HttpJSON, req.HttpsJSON, req.TcpJSON, req.TlsJSON, req.UnixJSON, req.UdpJSON, req.WebId, req.ReverseProxyJSON, req.NodeClusterId, req.IncludeNodesJSON, req.ExcludeNodesJSON, req.ServerGroupIds, req.UserPlanId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -193,6 +192,56 @@ func (this *ServerService) UpdateServerBasic(ctx context.Context, req *pb.Update
return this.Success() return this.Success()
} }
// UpdateServerGroupIds 修改服务所在分组
func (this *ServerService) UpdateServerGroupIds(ctx context.Context, req *pb.UpdateServerGroupIdsRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
if err != nil {
return nil, err
}
}
// 检查分组IDs
for _, groupId := range req.ServerGroupIds {
if userId > 0 {
err = models.SharedServerGroupDAO.CheckUserGroup(tx, userId, groupId)
if err != nil {
return nil, err
}
} else {
b, err := models.SharedServerGroupDAO.ExistsGroup(tx, groupId)
if err != nil {
return nil, err
}
if !b {
continue
}
}
}
// 增加默认分组
if userId > 0 {
config, err := models.SharedSysSettingDAO.ReadUserServerConfig(tx)
if err == nil && config.GroupId > 0 && !lists.ContainsInt64(req.ServerGroupIds, config.GroupId) {
req.ServerGroupIds = append(req.ServerGroupIds, config.GroupId)
}
}
// 修改
err = models.SharedServerDAO.UpdateServerGroupIds(tx, req.ServerId, req.ServerGroupIds)
if err != nil {
return nil, err
}
return this.Success()
}
// UpdateServerIsOn 修改服务是否启用 // UpdateServerIsOn 修改服务是否启用
func (this *ServerService) UpdateServerIsOn(ctx context.Context, req *pb.UpdateServerIsOnRequest) (*pb.RPCSuccess, error) { func (this *ServerService) UpdateServerIsOn(ctx context.Context, req *pb.UpdateServerIsOnRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0) _, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
@@ -200,7 +249,7 @@ func (this *ServerService) UpdateServerIsOn(ctx context.Context, req *pb.UpdateS
return nil, err return nil, err
} }
tx := this.NullTx() var tx = this.NullTx()
if userId > 0 { if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId) err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
@@ -833,8 +882,9 @@ func (this *ServerService) FindEnabledServer(ctx context.Context, req *pb.FindEn
continue continue
} }
pbGroups = append(pbGroups, &pb.ServerGroup{ pbGroups = append(pbGroups, &pb.ServerGroup{
Id: int64(group.Id), Id: int64(group.Id),
Name: group.Name, Name: group.Name,
UserId: int64(group.UserId),
}) })
} }
} }
@@ -1710,79 +1760,88 @@ func (this *ServerService) PurgeServerCache(ctx context.Context, req *pb.PurgeSe
} }
} }
if len(req.Domains) == 0 {
return nil, errors.New("'domains' field is required")
}
if len(req.Keys) == 0 && len(req.Prefixes) == 0 { if len(req.Keys) == 0 && len(req.Prefixes) == 0 {
return &pb.PurgeServerCacheResponse{IsOk: true}, nil return &pb.PurgeServerCacheResponse{IsOk: true}, nil
} }
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
var purgeResponse = &pb.PurgeServerCacheResponse{} var purgeResponse = &pb.PurgeServerCacheResponse{}
for _, domain := range req.Domains { var tx = this.NullTx()
servers, err := models.SharedServerDAO.FindAllEnabledServersWithDomain(tx, domain)
var taskType = "purge"
var tasks = []*pb.CreateHTTPCacheTaskRequest{}
if len(req.Keys) > 0 {
tasks = append(tasks, &pb.CreateHTTPCacheTaskRequest{
Type: taskType,
KeyType: "key",
Keys: req.Keys,
})
}
if len(req.Prefixes) > 0 {
tasks = append(tasks, &pb.CreateHTTPCacheTaskRequest{
Type: taskType,
KeyType: "prefix",
Keys: req.Prefixes,
})
}
var domainMap = map[string]*models.Server{} // domain name => *Server
for _, pbTask := range tasks {
// 创建任务
taskId, err := models.SharedHTTPCacheTaskDAO.CreateTask(tx, 0, pbTask.Type, pbTask.KeyType, "调用PURGE API")
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, server := range servers { var countKeys = 0
clusterId := int64(server.ClusterId)
if clusterId > 0 {
nodeIds, err := models.SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId)
if err != nil {
return nil, err
}
cachePolicyId, err := models.SharedNodeClusterDAO.FindClusterHTTPCachePolicyId(tx, clusterId, cacheMap) for _, key := range req.Keys {
if err != nil { if len(key) == 0 {
return nil, err continue
}
if cachePolicyId == 0 {
continue
}
cachePolicy, err := models.SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, cachePolicyId, cacheMap)
if err != nil {
return nil, err
}
if cachePolicy == nil {
continue
}
cachePolicyJSON, err := json.Marshal(cachePolicy)
if err != nil {
return nil, err
}
for _, nodeId := range nodeIds {
msg := &messageconfigs.PurgeCacheMessage{
CachePolicyJSON: cachePolicyJSON,
}
if len(req.Prefixes) > 0 {
msg.Type = messageconfigs.PurgeCacheMessageTypeDir
msg.Keys = req.Prefixes
} else {
msg.Type = messageconfigs.PurgeCacheMessageTypeFile
msg.Keys = req.Keys
}
msgJSON, err := json.Marshal(msg)
if err != nil {
return nil, err
}
resp, err := SendCommandToNode(nodeId, NextCommandRequestId(), messageconfigs.MessageCodePurgeCache, msgJSON, 10, false)
if err != nil {
return nil, err
}
if !resp.IsOk {
purgeResponse.IsOk = false
purgeResponse.Message = resp.Message
return purgeResponse, nil
}
}
} }
// 获取域名
var domain = utils.ParseDomainFromKey(key)
if len(domain) == 0 {
continue
}
// 查询所在集群
server, ok := domainMap[domain]
if !ok {
server, err = models.SharedServerDAO.FindEnabledServerWithDomain(tx, domain)
if err != nil {
return nil, err
}
if server == nil {
continue
}
domainMap[domain] = server
}
var serverClusterId = int64(server.ClusterId)
if serverClusterId == 0 {
continue
}
_, err = models.SharedHTTPCacheTaskKeyDAO.CreateKey(tx, taskId, key, pbTask.Type, pbTask.KeyType, serverClusterId)
if err != nil {
return nil, err
}
countKeys++
}
if countKeys == 0 {
// 如果没有有效的Key则直接完成
err = models.SharedHTTPCacheTaskDAO.UpdateTaskStatus(tx, taskId, true, true)
} else {
err = models.SharedHTTPCacheTaskDAO.UpdateTaskReady(tx, taskId)
}
if err != nil {
return nil, err
} }
} }
@@ -1955,9 +2014,11 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
DayTo: userPlan.DayTo, DayTo: userPlan.DayTo,
User: nil, User: nil,
Plan: &pb.Plan{ Plan: &pb.Plan{
Id: int64(plan.Id), Id: int64(plan.Id),
Name: plan.Name, Name: plan.Name,
PriceType: plan.PriceType, PriceType: plan.PriceType,
TrafficPriceJSON: plan.TrafficPrice,
TrafficLimitJSON: plan.TrafficLimit,
}, },
}, },
}, nil }, nil

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