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
function build() {
ROOT=$(dirname $0)
ROOT=$(dirname "$0")
NAME="edge-api"
DIST=$ROOT/"../dist/${NAME}"
OS=${1}
ARCH=${2}
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"
exit
fi
if [ -z $ARCH ]; then
if [ -z "$ARCH" ]; then
echo "usage: build.sh OS ARCH"
exit
fi
if [ -z $TAG ]; then
if [ -z "$TAG" ]; then
TAG="community"
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"
# 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} ..."
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'"
exit
fi
cd $ROOT"/../../EdgeNode/build"
cd "$ROOT""/../../EdgeNode/build" || exit
echo "=============================="
for arch in "${NODE_ARCHITECTS[@]}"; do
if [ ! -f $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" ]; then
./build.sh linux $arch $TAG
if [ ! -f "$ROOT""/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" ]; then
./build.sh linux "$arch" $TAG
else
echo "use built node linux/$arch/v${NodeVersion}"
fi
done
echo "=============================="
cd -
cd - || exit
rm -f $ROOT/deploy/*.zip
rm -f "$ROOT"/deploy/*.zip
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
# build edge-dns
if [ "$TAG" = "plus" ]; then
DNS_ROOT=$ROOT"/../../EdgeDNS"
if [ -d $DNS_ROOT ]; then
DNSNodeVersion=$(lookup-version $ROOT"/../../EdgeDNS/internal/const/const.go")
if [ -d "$DNS_ROOT" ]; then
DNSNodeVersion=$(lookup-version "$ROOT""/../../EdgeDNS/internal/const/const.go")
echo "building edge-dns ${DNSNodeVersion} ..."
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'"
exit
fi
cd $ROOT"/../../EdgeDNS/build"
cd "$ROOT""/../../EdgeDNS/build" || exit
echo "=============================="
architects=("amd64")
architects=("amd64" "arm64")
for arch in "${architects[@]}"; do
./build.sh linux $arch $TAG
./build.sh linux "$arch" $TAG
done
echo "=============================="
cd -
cd - || exit
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
fi
fi
@@ -78,48 +78,48 @@ function build() {
# build sql
if [ $TAG = "plus" ]; then
echo "building sql ..."
${ROOT}/sql.sh
"${ROOT}"/sql.sh
fi
# copy files
echo "copying ..."
if [ ! -d $DIST ]; then
mkdir $DIST
mkdir $DIST/bin
mkdir $DIST/configs
mkdir $DIST/logs
if [ ! -d "$DIST" ]; then
mkdir "$DIST"
mkdir "$DIST"/bin
mkdir "$DIST"/configs
mkdir "$DIST"/logs
fi
cp $ROOT/configs/api.template.yaml $DIST/configs/
cp $ROOT/configs/db.template.yaml $DIST/configs/
cp -R $ROOT/deploy $DIST/
rm -f $dist/deploy/.gitignore
cp -R $ROOT/installers $DIST/
cp -R $ROOT/resources $DIST/
rm -f $DIST/resources/ipdata/ip2region/global_region.csv
rm -f $DIST/resources/ipdata/ip2region/ip.merge.txt
cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/
cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/
cp -R "$ROOT"/deploy "$DIST/"
rm -f "$DIST"/deploy/.gitignore
cp -R "$ROOT"/installers "$DIST"/
cp -R "$ROOT"/resources "$DIST"/
rm -f "$DIST"/resources/ipdata/ip2region/global_region.csv
rm -f "$DIST"/resources/ipdata/ip2region/ip.merge.txt
# building edge installer
echo "building node installer ..."
architects=("amd64" "386" "arm64")
architects=("amd64" "arm64")
for arch in "${architects[@]}"; do
# 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
# building edge dns installer
echo "building dns node installer ..."
architects=("amd64" "386" "arm64")
architects=("amd64" "arm64")
for arch in "${architects[@]}"; do
# 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
# 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
find $DIST -name ".DS_Store" -delete
find $DIST -name ".gitignore" -delete
find "$DIST" -name ".DS_Store" -delete
find "$DIST" -name ".gitignore" -delete
echo "zip files"
cd "${DIST}/../" || exit
@@ -135,15 +135,15 @@ function build() {
function lookup-version() {
FILE=$1
VERSION_DATA=$(cat $FILE)
VERSION_DATA=$(cat "$FILE")
re="Version[ ]+=[ ]+\"([0-9.]+)\""
if [[ $VERSION_DATA =~ $re ]]; then
VERSION=${BASH_REMATCH[1]}
echo $VERSION
echo "$VERSION"
else
echo "could not match version"
exit
fi
}
build $1 $2 $3
build "$1" "$2" "$3"

View File

@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/apps"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
@@ -13,6 +14,7 @@ import (
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock"
"io/ioutil"
"log"
"os"
)
@@ -21,12 +23,12 @@ func main() {
if !Tea.IsTesting() {
Tea.Env = "prod"
}
app := apps.NewAppCmd()
var app = apps.NewAppCmd()
app.Version(teaconst.Version)
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() {
setupCmd := setup.NewSetupFromCmd()
var setupCmd = setup.NewSetupFromCmd()
err := setupCmd.Run()
result := maps.Map{}
if err != nil {
@@ -122,6 +124,43 @@ func main() {
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() {
nodes.NewAPINode().Start()

3
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
go 1.16
go 1.18
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
@@ -12,9 +12,8 @@ require (
github.com/go-acme/lego/v4 v4.5.2
github.com/go-sql-driver/mysql v1.5.0
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/json-iterator/go v1.1.12 // indirect
github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0
github.com/shirou/gopsutil/v3 v3.22.2
@@ -24,3 +23,25 @@ require (
google.golang.org/protobuf v1.27.1
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/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -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/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-20220322141208-22f88d04004d h1:e8fkTKras/RXQWECApM9fKlFWujjYjEClpshkmZmtYg=
github.com/iwind/TeaGo v0.0.0-20220322141208-22f88d04004d/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/TeaGo v0.0.0-20220408111647-f36b9bba3570 h1:zqz2FiMMkSHXWO1EsTRJDPTwX9xQ4uuyD5GAE4JGlhM=
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
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-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-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/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
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 格式化字符串中的变量
func (this *BaseStorage) FormatVariables(s string) string {
now := time.Now()
var now = time.Now()
return configutils.ParseVariables(s, func(varName string) (value string) {
switch varName {
case "year":

View File

@@ -1,7 +1,9 @@
package accesslogs
import (
"bytes"
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
@@ -95,7 +97,10 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
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()
if err != nil {
return err
@@ -111,7 +116,7 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
}
data, err := this.Marshal(accessLog)
if err != nil {
logs.Error(err)
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "marshal accesslog failed: "+err.Error())
continue
}
_, err = w.Write(data)
@@ -121,14 +126,15 @@ func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
_, err = w.Write([]byte("\n"))
if err != nil {
logs.Error(err)
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "write accesslog failed: "+err.Error())
}
}
_ = w.Close()
err = cmd.Wait()
if err != nil {
return err
return errors.New("send syslog failed: " + err.Error() + ", stderr: " + stderrBuffer.String())
}
return nil

View File

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

View File

@@ -58,15 +58,22 @@ func (this *APINodeDAO) EnableAPINode(tx *dbs.Tx, id int64) error {
}
// 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).
Pk(id).
Pk(nodeId).
Set("state", APINodeStateDisabled).
Update()
if err != nil {
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 查找启用中的条目

View File

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

View File

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

View File

@@ -107,7 +107,7 @@ func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, n
}
// 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)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
@@ -119,12 +119,16 @@ func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int6
query.Param("domain", domain)
}
if len(providerType) > 0 {
query.Attr("type", providerType)
}
return query.State(DNSProviderStateEnabled).
Count()
}
// 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)
if len(keyword) > 0 {
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.Param("domain", domain)
}
if len(providerType) > 0 {
query.Attr("type", providerType)
}
_, err = query.
State(DNSProviderStateEnabled).
Offset(offset).

View File

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

View File

@@ -1,9 +1,10 @@
package models
// 文件管理
// File 文件管理
type File struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
Code string `field:"code"` // 代号
UserId uint32 `field:"userId"` // 用户ID
Description string `field:"description"` // 文件描述
Filename string `field:"filename"` // 文件名
@@ -19,6 +20,7 @@ type File struct {
type FileOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
Code interface{} // 代号
UserId interface{} // 用户ID
Description interface{} // 文件描述
Filename interface{} // 文件名

View File

@@ -395,9 +395,14 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var locker = sync.Mutex{}
// 这里正则表达式中的括号不能轻易变更,因为后面有引用
// TODO 支持多个查询条件的组合,比如 status:200 proto:HTTP/1.1
var statusPrefixReg = regexp.MustCompile(`status:\s*(\d{3})\b`)
var statusRangeReg = regexp.MustCompile(`status:\s*(\d{3})-(\d{3})\b`)
var urlReg = regexp.MustCompile(`^(http|https)://`)
var requestPathReg = regexp.MustCompile(`requestPath:(\S+)`)
var protoReg = regexp.MustCompile(`proto:(\S+)`)
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
var count = len(tableQueries)
var wg = &sync.WaitGroup{}
@@ -509,13 +514,25 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
isSpecialKeyword = true
var matches = statusRangeReg.FindStringSubmatch(keyword)
query.Between("status", types.Int(matches[1]), types.Int(matches[2]))
// TODO 处理剩余的关键词
} else if statusPrefixReg.MatchString(keyword) { // status:200
isSpecialKeyword = true
var matches = statusPrefixReg.FindStringSubmatch(keyword)
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
u, err := url.Parse(keyword)
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 创建策略
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.GroupId = serverGroupId
op.ServerId = serverId
@@ -131,14 +131,31 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
if len(outboundJSON) > 0 {
op.Outbound = outboundJSON
}
op.UseLocalFirewall = true
{
synFloodJSON, err := json.Marshal(firewallconfigs.DefaultSYNFloodConfig())
if userId <= 0 && serverGroupId <=0 && serverId <= 0 {
// synFlood
var synFloodConfig = firewallconfigs.DefaultSYNFloodConfig()
synFloodJSON, err := json.Marshal(synFloodConfig)
if err != nil {
return 0, err
}
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)
@@ -160,8 +177,8 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
groupCodes = append(groupCodes, group.Code)
}
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
outboundConfig := &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
if templatePolicy.Inbound != nil {
for _, group := range templatePolicy.Inbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code)
@@ -207,6 +224,7 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
if err != nil {
return 0, err
}
return policyId, nil
}
@@ -268,6 +286,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
inboundJSON []byte,
outboundJSON []byte,
blockOptionsJSON []byte,
captchaOptionsJSON []byte,
mode firewallconfigs.FirewallMode,
useLocalFirewall bool,
synFloodConfig *firewallconfigs.SYNFloodConfig,
@@ -275,7 +294,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
if policyId <= 0 {
return errors.New("invalid policyId")
}
op := NewHTTPFirewallPolicyOperator()
var op = NewHTTPFirewallPolicyOperator()
op.Id = policyId
op.IsOn = isOn
op.Name = name
@@ -291,9 +310,12 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
} else {
op.Outbound = "null"
}
if len(blockOptionsJSON) > 0 {
if IsNotNull(blockOptionsJSON) {
op.BlockOptions = blockOptionsJSON
}
if IsNotNull(captchaOptionsJSON) {
op.CaptchaOptions = captchaOptionsJSON
}
if synFloodConfig != nil {
synFloodConfigJSON, err := json.Marshal(synFloodConfig)
@@ -456,7 +478,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
// Block动作配置
if IsNotNull(policy.BlockOptions) {
blockAction := &firewallconfigs.HTTPFirewallBlockAction{}
var blockAction = &firewallconfigs.HTTPFirewallBlockAction{}
err = json.Unmarshal(policy.BlockOptions, blockAction)
if err != nil {
return config, err
@@ -464,6 +486,16 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
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
if IsNotNull(policy.SynFlood) {
var synFloodConfig = &firewallconfigs.SYNFloodConfig{}
@@ -526,6 +558,7 @@ func (this *HTTPFirewallPolicyDAO) CheckUserFirewallPolicy(tx *dbs.Tx, userId in
}
// FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略
// TODO 改成通过 serverId 查询
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *dbs.Tx, ipListId int64) ([]int64, error) {
ones, err := this.Query(tx).
ResultPk().
@@ -544,6 +577,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *
}
// FindEnabledFirewallPolicyWithIPListId 查找使用某个IPList的策略
// TODO 改成通过 serverId 查询
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyWithIPListId(tx *dbs.Tx, ipListId int64) (*HTTPFirewallPolicy, error) {
one, err := this.Query(tx).
State(HTTPFirewallPolicyStateEnabled).

View File

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

View File

@@ -3,6 +3,7 @@ package models
import (
"encoding/json"
"errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"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 {
cacheMap.Put(cacheKey, config)
}
@@ -1168,6 +1179,35 @@ func (this *HTTPWebDAO) FindWebRequestScripts(tx *dbs.Tx, webId int64) (*serverc
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 通知更新
func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
// server

View File

@@ -37,6 +37,7 @@ type HTTPWeb struct {
MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠
RequestLimit dbs.JSON `field:"requestLimit"` // 请求限制
RequestScripts dbs.JSON `field:"requestScripts"` // 请求脚本
Uam dbs.JSON `field:"uam"` // UAM设置
}
type HTTPWebOperator struct {
@@ -73,6 +74,7 @@ type HTTPWebOperator struct {
MergeSlashes interface{} // 是否合并路径中的斜杠
RequestLimit interface{} // 请求限制
RequestScripts interface{} // 请求脚本
Uam interface{} // UAM设置
}
func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -93,6 +93,71 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
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
func (this *IPItemDAO) DisableIPItemsWithListId(tx *dbs.Tx, listId int64) error {
for {
@@ -142,14 +207,35 @@ func (this *IPItemDAO) FindEnabledIPItem(tx *dbs.Tx, id int64) (*IPItem, error)
// DeleteOldItem 根据IP删除以前的旧记录
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").
Attr("listId", listId).
Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo).
Delete()
// 这里不通知更新
return err
Set("state", IPItemStateEnabled).
FindAll()
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
@@ -202,6 +288,8 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
}
op.State = IPItemStateEnabled
op.UpdatedAt = time.Now().Unix()
err = this.Save(tx, op)
if err != nil {
return 0, err
@@ -453,7 +541,7 @@ func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error {
func (this *IPItemDAO) CleanExpiredIPItems(tx *dbs.Tx) error {
// 删除 N 天之前过期的数据
_, err := this.Query(tx).
Where("expiredAt<=:timestamp").
Where("(createdAt<=:timestamp AND updatedAt<=:timestamp)").
State(IPItemStateDisabled).
Param("timestamp", time.Now().Unix()-7*86400). // N 天之前过期的
Limit(10000). // 限制条数,防止数量过多导致超时

View File

@@ -1,6 +1,7 @@
package models
package models_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
@@ -14,7 +15,7 @@ func TestIPItemDAO_NotifyClustersUpdate(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
err := SharedIPItemDAO.NotifyUpdate(tx, 28)
err := models.SharedIPItemDAO.NotifyUpdate(tx, 28)
if err != nil {
t.Fatal(err)
}
@@ -25,7 +26,7 @@ func TestIPItemDAO_DisableIPItemsWithListId(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
err := SharedIPItemDAO.DisableIPItemsWithListId(tx, 67)
err := models.SharedIPItemDAO.DisableIPItemsWithListId(tx, 67)
if err != nil {
t.Fatal(err)
}
@@ -36,7 +37,7 @@ func TestIPItemDAO_ListIPItemsAfterVersion(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
_, err := SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
_, err := models.SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
if err != nil {
t.Fatal(err)
}
@@ -47,10 +48,10 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
var dao = NewIPItemDAO()
var dao = models.NewIPItemDAO()
var n = 10
for i := 0; i < n; i++ {
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", 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 {
t.Fatal(err)
}
@@ -62,3 +63,14 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
}
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 创建名单
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) {
op := NewIPListOperator()
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) {
var op = NewIPListOperator()
op.IsOn = true
op.UserId = userId
op.ServerId = serverId
op.State = IPListStateEnabled
op.Type = listType
op.Name = name
@@ -189,26 +190,25 @@ func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) e
return ErrNotFound
}
ok, err := this.Query(tx).
// 获取名单信息
listOne, err := this.Query(tx).
Pk(listId).
Attr("userId", userId).
Exist()
Result("userId", "serverId").
Find()
if err != nil {
return err
}
if ok {
if listOne == nil {
return ErrNotFound
}
var list = listOne.(*IPList)
if int64(list.UserId) == userId {
return nil
}
// 检查是否被用户的服务所使用
policyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
if err != nil {
return err
}
for _, policyId := range policyIds {
if SharedHTTPFirewallPolicyDAO.CheckUserFirewallPolicy(tx, userId, policyId) == nil {
return nil
}
var serverId = int64(list.ServerId)
if serverId > 0 {
return SharedServerDAO.CheckUserServer(tx, userId, serverId)
}
return ErrNotFound

View File

@@ -20,6 +20,39 @@ func TestIPListDAO_IncreaseVersion(t *testing.T) {
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) {
runtime.GOMAXPROCS(1)
@@ -32,3 +65,4 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
_, _ = dao.IncreaseVersion(tx)
}
}

View File

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

View File

@@ -90,9 +90,7 @@ func (this *MetricStatDAO) CreateStat(tx *dbs.Tx, hash string, clusterId int64,
"value": value,
})
if err != nil {
// 忽略 Error 1213: Deadlock found 错误
mysqlErr, ok := err.(*mysql.MySQLError)
if ok && mysqlErr.Number == 1213 {
if this.canIgnore(err) {
return nil
}
return err
@@ -135,6 +133,9 @@ func (this *MetricStatDAO) DeleteNodeItemStats(tx *dbs.Tx, nodeId int64, serverI
Attr("itemId", itemId).
Attr("time", time).
Delete()
if this.canIgnore(err) {
return nil
}
return err
}
@@ -690,7 +691,6 @@ func (this *MetricStatDAO) Clean(tx *dbs.Tx) error {
Table(table).
Attr("itemId", item.Id).
Lte("createdDay", expiresDay).
UseIndex("createdDay").
Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作
Delete()
return err
@@ -751,3 +751,18 @@ func (this *MetricStatDAO) mergeStats(stats []*MetricStat) (result []*MetricStat
}
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/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/go-sql-driver/mysql"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -55,7 +56,7 @@ func init() {
// 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 {
return this.Query(tx).
err := this.Query(tx).
Table(this.partialTable(serverId)).
InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId,
@@ -71,6 +72,10 @@ func (this *MetricSumStatDAO) UpdateSum(tx *dbs.Tx, clusterId int64, nodeId int6
"count": count,
"total": total,
})
if this.canIgnore(err) {
return nil
}
return err
}
// FindNodeServerSum 查找某个服务在某个节点上的统计数据
@@ -232,7 +237,6 @@ func (this *MetricSumStatDAO) Clean(tx *dbs.Tx) error {
Attr("itemId", item.Id).
Where("(createdDay IS NULL OR createdDay<:day)").
Param("day", expiresDay).
UseIndex("createdDay").
Limit(10_000). // 一次性不要删除太多,防止阻塞其他操作
Delete()
return err
@@ -277,3 +281,18 @@ func (this *MetricSumStatDAO) runBatch(f func(table string, locker *sync.Mutex)
wg.Wait()
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 禁用条目
func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, id int64) error {
func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx).
Pk(id).
Pk(nodeId).
Set("state", MonitorNodeStateDisabled).
Update()
return err
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleMonitor, nodeId)
}
// FindEnabledMonitorNode 查找启用中的条目

View File

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

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -141,10 +142,11 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// DNS设置
op.DnsDomainId = dnsDomainId
op.DnsName = dnsName
dnsConfig := &dnsconfigs.ClusterDNSConfig{
var dnsConfig = &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: true,
ServersAutoSync: true,
CNameRecords: []string{},
CNameAsDomain: true,
TTL: 0,
}
dnsJSON, err := json.Marshal(dnsConfig)
@@ -180,7 +182,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
}
// 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 {
return errors.New("invalid clusterId")
}
@@ -195,11 +197,6 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
nodeMaxThreads = 0
}
op.NodeMaxThreads = nodeMaxThreads
if nodeTCPMaxConnections < 0 {
nodeTCPMaxConnections = 0
}
op.NodeTCPMaxConnections = nodeTCPMaxConnections
op.AutoOpenPorts = autoOpenPorts
err := this.Save(tx, op)
@@ -467,7 +464,7 @@ func (this *NodeClusterDAO) ExistClusterDNSName(tx *dbs.Tx, dnsName string, excl
}
// 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 {
return errors.New("invalid clusterId")
}
@@ -507,6 +504,7 @@ func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsNam
ServersAutoSync: serversAutoSync,
CNameRecords: cnameRecords,
TTL: ttl,
CNameAsDomain: cnameAsDomain,
}
dnsJSON, err := json.Marshal(dnsConfig)
if err != nil {
@@ -922,7 +920,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx).
Pk(clusterId).
State(NodeClusterStateEnabled).
Result("timeZone", "nodeMaxThreads", "nodeTCPMaxConnections", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "isOn").
Result("id", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "isOn", "ddosProtection").
Find()
if err != nil || cluster == nil {
return nil, err
@@ -992,6 +990,104 @@ func (this *NodeClusterDAO) FindClusterWebPPolicy(tx *dbs.Tx, clusterId int64, c
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 通知更新
func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)

View File

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

View File

@@ -3,6 +3,7 @@ package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
)
// DecodeDNSConfig 解析DNS配置
@@ -12,12 +13,38 @@ func (this *NodeCluster) DecodeDNSConfig() (*dnsconfigs.ClusterDNSConfig, error)
return &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: false,
ServersAutoSync: false,
CNameAsDomain: true,
}, nil
}
dnsConfig := &dnsconfigs.ClusterDNSConfig{}
var dnsConfig = &dnsconfigs.ClusterDNSConfig{
CNameAsDomain: true,
}
err := json.Unmarshal(this.Dns, &dnsConfig)
if err != nil {
return nil, err
}
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/nodeconfigs"
"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/systemconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -99,7 +100,8 @@ func (this *NodeDAO) DisableNode(tx *dbs.Tx, nodeId int64) (err error) {
return err
}
return nil
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleNode, nodeId)
}
// FindEnabledNode 查找启用中的条目
@@ -360,6 +362,8 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
// 分组
if groupId > 0 {
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)
}
for _, clusterId := range one.(*Node).DecodeSecondaryClusterIds() {
if lists.ContainsInt64(result, clusterId) {
for _, secondaryClusterId := range one.(*Node).DecodeSecondaryClusterIds() {
if lists.ContainsInt64(result, secondaryClusterId) {
continue
}
result = append(result, clusterId)
result = append(result, secondaryClusterId)
}
return
}
@@ -661,16 +665,51 @@ func (this *NodeDAO) FindAllNodeIdsMatch(tx *dbs.Tx, clusterId int64, includeSec
}
// FindAllEnabledNodesWithClusterId 获取一个集群的所有节点
func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*Node, err error) {
_, err = this.Query(tx).
func (this *NodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondary bool) (result []*Node, err 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)
}
_, err = query.
State(NodeStateEnabled).
Attr("clusterId", clusterId).
DescPk().
Slice(&result).
FindAll()
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
func (this *NodeDAO) FindAllEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64) (result []int64, err error) {
ones, err := this.Query(tx).
@@ -757,6 +796,8 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
// 分组
if groupId > 0 {
query.Attr("groupId", groupId)
} else if groupId < 0 {
query.Attr("groupId", 0)
}
// 区域
@@ -773,11 +814,20 @@ func (this *NodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx,
}
// UpdateNodeStatus 更改节点状态
func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
_, err := this.Query(tx).
func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if nodeStatus == nil {
return nil
}
nodeStatusJSON, err := json.Marshal(nodeStatus)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(nodeId).
Set("isActive", true).
Set("status", string(statusJSON)).
Set("status", nodeStatusJSON).
Update()
return err
}
@@ -969,6 +1019,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
clusterIds = append(clusterIds, node.DecodeSecondaryClusterIds()...)
var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
if err != nil {
@@ -978,6 +1030,21 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
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)
if httpFirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap)
@@ -1012,7 +1079,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// 最大线程数、TCP连接数
if clusterIndex == 0 {
config.MaxThreads = int(nodeCluster.NodeMaxThreads)
config.TCPMaxConnections = int(nodeCluster.NodeTCPMaxConnections)
config.DDoSProtection = nodeCluster.DecodeDDoSProtection()
config.AutoOpenPorts = nodeCluster.AutoOpenPorts == 1
}
@@ -1026,6 +1093,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
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++
}
@@ -1070,6 +1147,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
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)
if err != nil {
@@ -1134,6 +1221,16 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
}
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)
if err != nil {
@@ -1400,6 +1497,49 @@ func (this *NodeDAO) UpdateNodeDNS(tx *dbs.Tx, nodeId int64, routes map[int64][]
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 设置系统信息
func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) error {
if nodeId <= 0 {
@@ -1737,6 +1877,53 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
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 通知节点相关更新
func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
// 这里只需要通知单个集群即可,因为节点是公用的,更新一个就相当于更新了所有

View File

@@ -5,6 +5,7 @@ import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
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/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -375,7 +376,15 @@ func (this *NodeIPAddressDAO) ListEnabledIPAddresses(tx *dbs.Tx, role string, no
}
// 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).
State(NodeIPAddressStateEnabled).
Attr("role", role).
@@ -385,6 +394,14 @@ func (this *NodeIPAddressDAO) FindAllAccessibleIPAddressesWithClusterId(tx *dbs.
Param("clusterId", clusterId).
Slice(&result).
FindAll()
if err != nil {
return
}
if cacheMap != nil {
cacheMap.Put(cacheKey, result)
}
return
}

View File

@@ -360,3 +360,12 @@ func (this *NodeLogDAO) UpdateAllNodeLogsRead(tx *dbs.Tx) error {
Set("isRead", true).
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"` // 状态
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
MaxCPU uint32 `field:"maxCPU"` // 可以使用的最多CPU
MaxThreads uint32 `field:"maxThreads"` // 最大线程数
DdosProtection dbs.JSON `field:"ddosProtection"` // DDOS配置
DnsRoutes dbs.JSON `field:"dnsRoutes"` // DNS线路设置
MaxCacheDiskCapacity dbs.JSON `field:"maxCacheDiskCapacity"` // 硬盘缓存容量
MaxCacheMemoryCapacity dbs.JSON `field:"maxCacheMemoryCapacity"` // 内存缓存容量
CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
}
type NodeOperator struct {
@@ -65,10 +68,13 @@ type NodeOperator struct {
State interface{} // 状态
ConnectedAPINodes interface{} // 当前连接的API节点
MaxCPU interface{} // 可以使用的最多CPU
MaxThreads interface{} // 最大线程数
DdosProtection interface{} // DDOS配置
DnsRoutes interface{} // DNS线路设置
MaxCacheDiskCapacity interface{} // 硬盘缓存容量
MaxCacheMemoryCapacity interface{} // 内存缓存容量
CacheDiskDir interface{} // 缓存目录
DnsResolver interface{} // DNS解析器
}
func NewNodeOperator() *NodeOperator {

View File

@@ -3,6 +3,8 @@ package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"sort"
"time"
)
@@ -97,6 +99,7 @@ func (this *Node) DecodeSecondaryClusterIds() []int64 {
return result
}
// AllClusterIds 获取所属集群IDs
func (this *Node) AllClusterIds() []int64 {
var result = []int64{}
@@ -108,3 +111,60 @@ func (this *Node) AllClusterIds() []int64 {
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
const (
NodeTaskTypeConfigChanged NodeTaskType = "configChanged"
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged"
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged"
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged"
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged"
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged"
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged"
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged"
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged"
// NS相关

View File

@@ -52,16 +52,23 @@ func (this *NSNodeDAO) EnableNSNode(tx *dbs.Tx, id int64) error {
}
// 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).
Pk(id).
Pk(nodeId).
Set("state", NSNodeStateDisabled).
Update()
if err != nil {
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 查找启用中的条目
@@ -339,13 +346,19 @@ func (this *NSNodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstall
}
// UpdateNodeStatus 更改节点状态
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
if statusJSON == nil {
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if nodeStatus == nil {
return nil
}
_, err := this.Query(tx).
nodeStatusJSON, err := json.Marshal(nodeStatus)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(nodeId).
Set("status", string(statusJSON)).
Set("status", nodeStatusJSON).
Update()
return err
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -83,13 +83,3 @@ func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
}
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,
reverseProxyJSON []byte,
clusterId int64,
includeNodesJSON string,
excludeNodesJSON string,
includeNodesJSON []byte,
excludeNodesJSON []byte,
groupIds []int64,
userPlanId int64) (serverId int64, err error) {
var op = NewServerOperator()
@@ -206,15 +206,15 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
op.Udp = udpJSON
}
op.WebId = webId
if len(reverseProxyJSON) > 0 {
if IsNotNull(reverseProxyJSON) {
op.ReverseProxy = reverseProxyJSON
}
op.ClusterId = clusterId
if len(includeNodesJSON) > 0 {
if IsNotNull(includeNodesJSON) {
op.IncludeNodes = includeNodesJSON
}
if len(excludeNodesJSON) > 0 {
if IsNotNull(excludeNodesJSON) {
op.ExcludeNodes = excludeNodesJSON
}
@@ -338,12 +338,31 @@ func (this *ServerDAO) UpdateServerBasic(tx *dbs.Tx, serverId int64, name string
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 设置用户相关的基本信息
func (this *ServerDAO) UpdateUserServerBasic(tx *dbs.Tx, serverId int64, name string) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
op := NewServerOperator()
var op = NewServerOperator()
op.Id = serverId
op.Name = name
@@ -752,8 +771,9 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
}
if len(keyword) > 0 {
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("serverId", keyword).
Param("keyword", dbutils.QuoteLike(keyword))
} else {
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 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("serverId", keyword).
Param("keyword", dbutils.QuoteLike(keyword))
} else {
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
}
config := &serverconfigs.ServerConfig{}
var config = &serverconfigs.ServerConfig{}
config.Id = int64(server.Id)
config.ClusterId = int64(server.ClusterId)
config.UserId = int64(server.UserId)
config.Type = server.Type
config.IsOn = server.IsOn
config.Name = server.Name
@@ -1044,7 +1066,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// ServerNames
if IsNotNull(server.ServerNames) {
serverNames := []*serverconfigs.ServerNameConfig{}
var serverNames = []*serverconfigs.ServerNameConfig{}
err := json.Unmarshal(server.ServerNames, &serverNames)
if err != nil {
return nil, err
@@ -1060,20 +1082,29 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
return nil, err
}
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)
if err != nil {
return nil, err
}
if domain != nil {
cname := server.DnsName + "." + domain.Name
config.AliasServerNames = append(config.AliasServerNames, cname)
var cname = server.DnsName + "." + domain.Name
config.CNameDomain = cname
if clusterDNSConfig.CNameAsDomain {
config.CNameAsDomain = true
config.AliasServerNames = append(config.AliasServerNames, cname)
}
}
}
}
// HTTP
if IsNotNull(server.Http) {
httpConfig := &serverconfigs.HTTPProtocolConfig{}
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal(server.Http, httpConfig)
if err != nil {
return nil, err
@@ -1083,7 +1114,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// HTTPS
if IsNotNull(server.Https) {
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(server.Https, httpsConfig)
if err != nil {
return nil, err
@@ -1105,7 +1136,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// TCP
if IsNotNull(server.Tcp) {
tcpConfig := &serverconfigs.TCPProtocolConfig{}
var tcpConfig = &serverconfigs.TCPProtocolConfig{}
err := json.Unmarshal(server.Tcp, tcpConfig)
if err != nil {
return nil, err
@@ -1115,7 +1146,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// TLS
if IsNotNull(server.Tls) {
tlsConfig := &serverconfigs.TLSProtocolConfig{}
var tlsConfig = &serverconfigs.TLSProtocolConfig{}
err := json.Unmarshal(server.Tls, tlsConfig)
if err != nil {
return nil, err
@@ -1137,7 +1168,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// Unix
if IsNotNull(server.Unix) {
unixConfig := &serverconfigs.UnixProtocolConfig{}
var unixConfig = &serverconfigs.UnixProtocolConfig{}
err := json.Unmarshal(server.Unix, unixConfig)
if err != nil {
return nil, err
@@ -1147,7 +1178,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// UDP
if IsNotNull(server.Udp) {
udpConfig := &serverconfigs.UDPProtocolConfig{}
var udpConfig = &serverconfigs.UDPProtocolConfig{}
err := json.Unmarshal(server.Udp, udpConfig)
if err != nil {
return nil, err
@@ -1168,7 +1199,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
// ReverseProxy
if IsNotNull(server.ReverseProxy) {
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
err := json.Unmarshal(server.ReverseProxy, reverseProxyRef)
if err != nil {
return nil, err
@@ -1185,7 +1216,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
}
// WAF策略
clusterId := int64(server.ClusterId)
var clusterId = int64(server.ClusterId)
httpFirewallPolicyId, err := SharedNodeClusterDAO.FindClusterHTTPFirewallPolicyId(tx, clusterId, cacheMap)
if err != nil {
return nil, err
@@ -1476,6 +1507,7 @@ func (this *ServerDAO) FindAllServersDNSWithClusterId(tx *dbs.Tx, clusterId int6
}
// FindAllEnabledServersWithDomain 根据域名查找服务
// TODO 需要改成使用plainServerNames
func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string) (result []*Server, err error) {
if len(domain) == 0 {
return
@@ -1523,6 +1555,49 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
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 重新生成子域名
func (this *ServerDAO) GenerateServerDNSName(tx *dbs.Tx, serverId int64) (string, error) {
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 {
_, err := this.Query(tx).
Attr("userId", userId).
Attr("userPlanId", 0).
Set("clusterId", newClusterId).
Update()
if err != nil {

View File

@@ -3,6 +3,7 @@ package models_test
import (
"crypto/md5"
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
@@ -10,10 +11,36 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"testing"
"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) {
dbs.NotifyReady()
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) {
dbs.NotifyReady()

View File

@@ -410,6 +410,17 @@ func (this *ServerGroupDAO) CheckUserGroup(tx *dbs.Tx, userId int64, groupId int
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 通知更新
func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
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
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}
@@ -257,7 +257,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
percentile = 100
}
}
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}
@@ -306,7 +306,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位
var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}
@@ -343,7 +343,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位
var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}
@@ -361,7 +361,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
// 百分位
var percentile = 95
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}
@@ -382,7 +382,7 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
percentile = 100
}
}
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
percentileBytes, err := SharedServerBandwidthStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
if err != nil {
return err
}

View File

@@ -169,7 +169,7 @@ func (this *UserDAO) UpdateUser(tx *dbs.Tx, userId int64, username string, passw
if userId <= 0 {
return errors.New("invalid userId")
}
op := NewUserOperator()
var op = NewUserOperator()
op.Id = userId
op.Username = username
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 禁用条目
func (this *UserNodeDAO) DisableUserNode(tx *dbs.Tx, id int64) error {
func (this *UserNodeDAO) DisableUserNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx).
Pk(id).
Pk(nodeId).
Set("state", UserNodeStateDisabled).
Update()
return err
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleUser, nodeId)
}
// FindEnabledUserNode 查找启用中的条目
@@ -254,13 +259,19 @@ func (this *UserNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
}
// UpdateNodeStatus 更改节点状态
func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
if len(statusJSON) == 0 {
func (this *UserNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if nodeStatus == nil {
return nil
}
_, err := this.Query(tx).
nodeStatusJSON, err := json.Marshal(nodeStatus)
if err != nil {
return err
}
_, err = this.Query(tx).
Pk(nodeId).
Set("status", string(statusJSON)).
Set("status", nodeStatusJSON).
Update()
return err
}

View File

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

View File

@@ -71,7 +71,7 @@ func TestAliDNSProvider_AddRecord(t *testing.T) {
Name: "test",
Type: dnstypes.RecordTypeA,
Value: "192.168.1.100",
Route: "unicom",
Route: "aliyun_r_cn-beijing",
})
if err != nil {
t.Fatal(err)
@@ -103,7 +103,7 @@ func testAliDNSProvider() (ProviderInterface, error) {
if err != nil {
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 {
return nil, err
}

View File

@@ -11,7 +11,6 @@ const (
ProviderTypeDNSPod ProviderType = "dnspod" // DNSPod
ProviderTypeAliDNS ProviderType = "alidns" // 阿里云DNS
ProviderTypeHuaweiDNS ProviderType = "huaweiDNS" // 华为DNS
ProviderTypeDNSCom ProviderType = "dnscom" // dns.com
ProviderTypeCloudFlare ProviderType = "cloudFlare" // CloudFlare DNS
ProviderTypeLocalEdgeDNS ProviderType = "localEdgeDNS" // 和当前系统集成的EdgeDNS
ProviderTypeUserEdgeDNS ProviderType = "userEdgeDNS" // 通过API连接的EdgeDNS
@@ -36,11 +35,6 @@ func FindAllProviderTypes() []maps.Map {
"code": ProviderTypeHuaweiDNS,
"description": "华为云解析DNS。",
},
/**{
"name": "帝恩思DNS.COM",
"code": ProviderTypeDNSCom,
"description": "DNS.com提供的DNS服务。",
},**/
{
"name": "CloudFlare DNS",
"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 (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/accesslogs"
"github.com/TeaOSLab/EdgeAPI/internal/configs"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
@@ -15,6 +15,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/rpc"
"github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
@@ -35,6 +36,7 @@ import (
"runtime"
"sort"
"strconv"
"strings"
"sync"
"time"
@@ -51,12 +53,18 @@ type APINode struct {
sock *gosock.Sock
isStarting bool
issues []*StartIssue
issuesFile string
}
func NewAPINode() *APINode {
return &APINode{
serviceInstanceMap: map[string]interface{}{},
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()))
// 检查数据库连接
err := this.checkDB()
if err != nil {
logs.Println("[API_NODE]" + err.Error())
return
}
// 保存启动过程中的问题,以便于查看
defer func() {
this.saveIssues()
}()
// 本地Sock
logs.Println("[API_NODE]listening sock ...")
err = this.listenSock()
err := this.listenSock()
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
}
@@ -84,7 +101,9 @@ func (this *APINode) Start() {
logs.Println("[API_NODE]auto upgrading ...")
err = this.autoUpgrade()
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
}
@@ -105,7 +124,9 @@ func (this *APINode) Start() {
logs.Println("[API_NODE]reading api config ...")
config, err := configs.SharedAPIConfig()
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
}
sharedAPIConfig = config
@@ -113,15 +134,23 @@ func (this *APINode) Start() {
// 校验
apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINodeWithUniqueIdAndSecret(nil, config.NodeId, config.Secret)
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
}
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
}
config.SetNumberId(int64(apiNode.Id))
// 清除上一次启动错误
// 这个错误文件可能不存在,不需要处理错误
_ = os.Remove(this.issuesFile)
// 设置rlimit
_ = utils.SetRLimit(1024 * 1024)
@@ -138,10 +167,12 @@ func (this *APINode) Start() {
// 监听RPC服务
remotelogs.Println("API_NODE", "starting RPC server ...")
isListening := this.listenPorts(apiNode)
var isListening = this.listenPorts(apiNode)
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
}
@@ -154,9 +185,8 @@ func (this *APINode) Start() {
// Daemon 实现守护进程
func (this *APINode) Daemon() {
path := os.TempDir() + "/edge-api.sock"
isDebug := lists.ContainsString(os.Args, "debug")
isDebug = true
var path = os.TempDir() + "/" + teaconst.ProcessName + ".sock"
var isDebug = lists.ContainsString(os.Args, "debug")
for {
conn, err := net.DialTimeout("unix", path, 1*time.Second)
if err != nil {
@@ -199,14 +229,14 @@ func (this *APINode) Daemon() {
// InstallSystemService 安装系统服务
func (this *APINode) InstallSystemService() error {
shortName := teaconst.SystemdServiceName
var shortName = teaconst.SystemdServiceName
exe, err := os.Executable()
if err != nil {
return err
}
manager := utils.NewServiceManager(shortName, teaconst.ProductName)
var manager = utils.NewServiceManager(shortName, teaconst.ProductName)
err = manager.Install(exe, []string{})
if err != nil {
return err
@@ -242,21 +272,33 @@ func (this *APINode) checkDB() error {
return err
}
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]reconnecting to database (" + fmt.Sprintf("%.1f", float32(i*100)/float32(maxTries+1)) + "%) ...")
// 第一次测试连接
_, err = db.Exec("SELECT 1")
if err != nil {
var errString = "check database connection failed: " + err.Error()
logs.Println("[API_NODE]" + errString)
this.addStartIssue("db", errString, this.dbIssueSuggestion(errString))
// 多次尝试
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
config := &dbs.Config{}
var config = &dbs.Config{}
configData, err := ioutil.ReadFile(Tea.ConfigFile("db.yaml"))
if err != nil {
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
}
// 添加启动相关的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) {
{
instance := this.serviceInstance(&services.APITokenService{}).(*services.APITokenService)
var instance = this.serviceInstance(&services.APITokenService{}).(*services.APITokenService)
pb.RegisterAPITokenServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.AdminService{}).(*services.AdminService)
var instance = this.serviceInstance(&services.AdminService{}).(*services.AdminService)
pb.RegisterAdminServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeGrantService{}).(*services.NodeGrantService)
var instance = this.serviceInstance(&services.NodeGrantService{}).(*services.NodeGrantService)
pb.RegisterNodeGrantServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerService{}).(*services.ServerService)
var instance = this.serviceInstance(&services.ServerService{}).(*services.ServerService)
pb.RegisterServerServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeService{}).(*services.NodeService)
var instance = this.serviceInstance(&services.NodeService{}).(*services.NodeService)
pb.RegisterNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeClusterService{}).(*services.NodeClusterService)
var instance = this.serviceInstance(&services.NodeClusterService{}).(*services.NodeClusterService)
pb.RegisterNodeClusterServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeIPAddressService{}).(*services.NodeIPAddressService)
var instance = this.serviceInstance(&services.NodeIPAddressService{}).(*services.NodeIPAddressService)
pb.RegisterNodeIPAddressServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeIPAddressLogService{}).(*services.NodeIPAddressLogService)
var instance = this.serviceInstance(&services.NodeIPAddressLogService{}).(*services.NodeIPAddressLogService)
pb.RegisterNodeIPAddressLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeIPAddressThresholdService{}).(*services.NodeIPAddressThresholdService)
var instance = this.serviceInstance(&services.NodeIPAddressThresholdService{}).(*services.NodeIPAddressThresholdService)
pb.RegisterNodeIPAddressThresholdServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.APINodeService{}).(*services.APINodeService)
var instance = this.serviceInstance(&services.APINodeService{}).(*services.APINodeService)
pb.RegisterAPINodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService)
var instance = this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService)
pb.RegisterAPIMethodStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.OriginService{}).(*services.OriginService)
var instance = this.serviceInstance(&services.OriginService{}).(*services.OriginService)
pb.RegisterOriginServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPWebService{}).(*services.HTTPWebService)
var instance = this.serviceInstance(&services.HTTPWebService{}).(*services.HTTPWebService)
pb.RegisterHTTPWebServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ReverseProxyService{}).(*services.ReverseProxyService)
var instance = this.serviceInstance(&services.ReverseProxyService{}).(*services.ReverseProxyService)
pb.RegisterReverseProxyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPGzipService{}).(*services.HTTPGzipService)
var instance = this.serviceInstance(&services.HTTPGzipService{}).(*services.HTTPGzipService)
pb.RegisterHTTPGzipServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPHeaderPolicyService{}).(*services.HTTPHeaderPolicyService)
var instance = this.serviceInstance(&services.HTTPHeaderPolicyService{}).(*services.HTTPHeaderPolicyService)
pb.RegisterHTTPHeaderPolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPHeaderService{}).(*services.HTTPHeaderService)
var instance = this.serviceInstance(&services.HTTPHeaderService{}).(*services.HTTPHeaderService)
pb.RegisterHTTPHeaderServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPPageService{}).(*services.HTTPPageService)
var instance = this.serviceInstance(&services.HTTPPageService{}).(*services.HTTPPageService)
pb.RegisterHTTPPageServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPAccessLogPolicyService{}).(*services.HTTPAccessLogPolicyService)
var instance = this.serviceInstance(&services.HTTPAccessLogPolicyService{}).(*services.HTTPAccessLogPolicyService)
pb.RegisterHTTPAccessLogPolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPCachePolicyService{}).(*services.HTTPCachePolicyService)
var instance = this.serviceInstance(&services.HTTPCachePolicyService{}).(*services.HTTPCachePolicyService)
pb.RegisterHTTPCachePolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPFirewallPolicyService{}).(*services.HTTPFirewallPolicyService)
var instance = this.serviceInstance(&services.HTTPFirewallPolicyService{}).(*services.HTTPFirewallPolicyService)
pb.RegisterHTTPFirewallPolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.FirewallService{}).(*services.FirewallService)
var instance = this.serviceInstance(&services.FirewallService{}).(*services.FirewallService)
pb.RegisterFirewallServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPLocationService{}).(*services.HTTPLocationService)
var instance = this.serviceInstance(&services.HTTPLocationService{}).(*services.HTTPLocationService)
pb.RegisterHTTPLocationServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPWebsocketService{}).(*services.HTTPWebsocketService)
var instance = this.serviceInstance(&services.HTTPWebsocketService{}).(*services.HTTPWebsocketService)
pb.RegisterHTTPWebsocketServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPRewriteRuleService{}).(*services.HTTPRewriteRuleService)
var instance = this.serviceInstance(&services.HTTPRewriteRuleService{}).(*services.HTTPRewriteRuleService)
pb.RegisterHTTPRewriteRuleServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.SSLCertService{}).(*services.SSLCertService)
var instance = this.serviceInstance(&services.SSLCertService{}).(*services.SSLCertService)
pb.RegisterSSLCertServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.SSLPolicyService{}).(*services.SSLPolicyService)
var instance = this.serviceInstance(&services.SSLPolicyService{}).(*services.SSLPolicyService)
pb.RegisterSSLPolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.SysSettingService{}).(*services.SysSettingService)
var instance = this.serviceInstance(&services.SysSettingService{}).(*services.SysSettingService)
pb.RegisterSysSettingServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPFirewallRuleGroupService{}).(*services.HTTPFirewallRuleGroupService)
var instance = this.serviceInstance(&services.HTTPFirewallRuleGroupService{}).(*services.HTTPFirewallRuleGroupService)
pb.RegisterHTTPFirewallRuleGroupServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPFirewallRuleSetService{}).(*services.HTTPFirewallRuleSetService)
var instance = this.serviceInstance(&services.HTTPFirewallRuleSetService{}).(*services.HTTPFirewallRuleSetService)
pb.RegisterHTTPFirewallRuleSetServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DBNodeService{}).(*services.DBNodeService)
var instance = this.serviceInstance(&services.DBNodeService{}).(*services.DBNodeService)
pb.RegisterDBNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeLogService{}).(*services.NodeLogService)
var instance = this.serviceInstance(&services.NodeLogService{}).(*services.NodeLogService)
pb.RegisterNodeLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeLoginService{}).(*services.NodeLoginService)
var instance = this.serviceInstance(&services.NodeLoginService{}).(*services.NodeLoginService)
pb.RegisterNodeLoginServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPAccessLogService{}).(*services.HTTPAccessLogService)
var instance = this.serviceInstance(&services.HTTPAccessLogService{}).(*services.HTTPAccessLogService)
pb.RegisterHTTPAccessLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageService{}).(*services.MessageService)
var instance = this.serviceInstance(&services.MessageService{}).(*services.MessageService)
pb.RegisterMessageServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageRecipientService{}).(*services.MessageRecipientService)
var instance = this.serviceInstance(&services.MessageRecipientService{}).(*services.MessageRecipientService)
pb.RegisterMessageRecipientServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageReceiverService{}).(*services.MessageReceiverService)
var instance = this.serviceInstance(&services.MessageReceiverService{}).(*services.MessageReceiverService)
pb.RegisterMessageReceiverServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageMediaService{}).(*services.MessageMediaService)
var instance = this.serviceInstance(&services.MessageMediaService{}).(*services.MessageMediaService)
pb.RegisterMessageMediaServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageRecipientGroupService{}).(*services.MessageRecipientGroupService)
var instance = this.serviceInstance(&services.MessageRecipientGroupService{}).(*services.MessageRecipientGroupService)
pb.RegisterMessageRecipientGroupServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageMediaInstanceService{}).(*services.MessageMediaInstanceService)
var instance = this.serviceInstance(&services.MessageMediaInstanceService{}).(*services.MessageMediaInstanceService)
pb.RegisterMessageMediaInstanceServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageTaskService{}).(*services.MessageTaskService)
var instance = this.serviceInstance(&services.MessageTaskService{}).(*services.MessageTaskService)
pb.RegisterMessageTaskServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MessageTaskLogService{}).(*services.MessageTaskLogService)
var instance = this.serviceInstance(&services.MessageTaskLogService{}).(*services.MessageTaskLogService)
pb.RegisterMessageTaskLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeGroupService{}).(*services.NodeGroupService)
var instance = this.serviceInstance(&services.NodeGroupService{}).(*services.NodeGroupService)
pb.RegisterNodeGroupServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeRegionService{}).(*services.NodeRegionService)
var instance = this.serviceInstance(&services.NodeRegionService{}).(*services.NodeRegionService)
pb.RegisterNodeRegionServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodePriceItemService{}).(*services.NodePriceItemService)
var instance = this.serviceInstance(&services.NodePriceItemService{}).(*services.NodePriceItemService)
pb.RegisterNodePriceItemServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerGroupService{}).(*services.ServerGroupService)
var instance = this.serviceInstance(&services.ServerGroupService{}).(*services.ServerGroupService)
pb.RegisterServerGroupServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.IPLibraryService{}).(*services.IPLibraryService)
var instance = this.serviceInstance(&services.IPLibraryService{}).(*services.IPLibraryService)
pb.RegisterIPLibraryServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
var instance = this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
pb.RegisterFileChunkServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.FileService{}).(*services.FileService)
var instance = this.serviceInstance(&services.FileService{}).(*services.FileService)
pb.RegisterFileServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.RegionCountryService{}).(*services.RegionCountryService)
var instance = this.serviceInstance(&services.RegionCountryService{}).(*services.RegionCountryService)
pb.RegisterRegionCountryServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.RegionProvinceService{}).(*services.RegionProvinceService)
var instance = this.serviceInstance(&services.RegionProvinceService{}).(*services.RegionProvinceService)
pb.RegisterRegionProvinceServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.RegionCityService{}).(*services.RegionCityService)
var instance = this.serviceInstance(&services.RegionCityService{}).(*services.RegionCityService)
pb.RegisterRegionCityServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.RegionProviderService{}).(*services.RegionProviderService)
var instance = this.serviceInstance(&services.RegionProviderService{}).(*services.RegionProviderService)
pb.RegisterRegionProviderServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.IPListService{}).(*services.IPListService)
var instance = this.serviceInstance(&services.IPListService{}).(*services.IPListService)
pb.RegisterIPListServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.IPItemService{}).(*services.IPItemService)
var instance = this.serviceInstance(&services.IPItemService{}).(*services.IPItemService)
pb.RegisterIPItemServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.LogService{}).(*services.LogService)
var instance = this.serviceInstance(&services.LogService{}).(*services.LogService)
pb.RegisterLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DNSProviderService{}).(*services.DNSProviderService)
var instance = this.serviceInstance(&services.DNSProviderService{}).(*services.DNSProviderService)
pb.RegisterDNSProviderServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DNSDomainService{}).(*services.DNSDomainService)
var instance = this.serviceInstance(&services.DNSDomainService{}).(*services.DNSDomainService)
pb.RegisterDNSDomainServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DNSService{}).(*services.DNSService)
var instance = this.serviceInstance(&services.DNSService{}).(*services.DNSService)
pb.RegisterDNSServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ACMEUserService{}).(*services.ACMEUserService)
var instance = this.serviceInstance(&services.ACMEUserService{}).(*services.ACMEUserService)
pb.RegisterACMEUserServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ACMETaskService{}).(*services.ACMETaskService)
var instance = this.serviceInstance(&services.ACMETaskService{}).(*services.ACMETaskService)
pb.RegisterACMETaskServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ACMEAuthenticationService{}).(*services.ACMEAuthenticationService)
var instance = this.serviceInstance(&services.ACMEAuthenticationService{}).(*services.ACMEAuthenticationService)
pb.RegisterACMEAuthenticationServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ACMEProviderService{}).(*services.ACMEProviderService)
var instance = this.serviceInstance(&services.ACMEProviderService{}).(*services.ACMEProviderService)
pb.RegisterACMEProviderServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ACMEProviderAccountService{}).(*services.ACMEProviderAccountService)
var instance = this.serviceInstance(&services.ACMEProviderAccountService{}).(*services.ACMEProviderAccountService)
pb.RegisterACMEProviderAccountServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.UserService{}).(*services.UserService)
var instance = this.serviceInstance(&services.UserService{}).(*services.UserService)
pb.RegisterUserServiceServer(server, 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)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.UserBillService{}).(*services.UserBillService)
var instance = this.serviceInstance(&services.UserBillService{}).(*services.UserBillService)
pb.RegisterUserBillServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
var instance = this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
pb.RegisterServerBillServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
var instance = this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
pb.RegisterUserNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.LoginService{}).(*services.LoginService)
var instance = this.serviceInstance(&services.LoginService{}).(*services.LoginService)
pb.RegisterLoginServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.UserAccessKeyService{}).(*services.UserAccessKeyService)
var instance = this.serviceInstance(&services.UserAccessKeyService{}).(*services.UserAccessKeyService)
pb.RegisterUserAccessKeyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.SysLockerService{}).(*services.SysLockerService)
var instance = this.serviceInstance(&services.SysLockerService{}).(*services.SysLockerService)
pb.RegisterSysLockerServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeTaskService{}).(*services.NodeTaskService)
var instance = this.serviceInstance(&services.NodeTaskService{}).(*services.NodeTaskService)
pb.RegisterNodeTaskServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeValueService{}).(*services.NodeValueService)
var instance = this.serviceInstance(&services.NodeValueService{}).(*services.NodeValueService)
pb.RegisterNodeValueServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DBService{}).(*services.DBService)
var instance = this.serviceInstance(&services.DBService{}).(*services.DBService)
pb.RegisterDBServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerRegionCityMonthlyStatService{}).(*services.ServerRegionCityMonthlyStatService)
var instance = this.serviceInstance(&services.ServerRegionCityMonthlyStatService{}).(*services.ServerRegionCityMonthlyStatService)
pb.RegisterServerRegionCityMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerRegionCountryMonthlyStatService{}).(*services.ServerRegionCountryMonthlyStatService)
var instance = this.serviceInstance(&services.ServerRegionCountryMonthlyStatService{}).(*services.ServerRegionCountryMonthlyStatService)
pb.RegisterServerRegionCountryMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerRegionProvinceMonthlyStatService{}).(*services.ServerRegionProvinceMonthlyStatService)
var instance = this.serviceInstance(&services.ServerRegionProvinceMonthlyStatService{}).(*services.ServerRegionProvinceMonthlyStatService)
pb.RegisterServerRegionProvinceMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerRegionProviderMonthlyStatService{}).(*services.ServerRegionProviderMonthlyStatService)
var instance = this.serviceInstance(&services.ServerRegionProviderMonthlyStatService{}).(*services.ServerRegionProviderMonthlyStatService)
pb.RegisterServerRegionProviderMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService)
var instance = this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService)
pb.RegisterServerClientSystemMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerClientBrowserMonthlyStatService{}).(*services.ServerClientBrowserMonthlyStatService)
var instance = this.serviceInstance(&services.ServerClientBrowserMonthlyStatService{}).(*services.ServerClientBrowserMonthlyStatService)
pb.RegisterServerClientBrowserMonthlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerHTTPFirewallDailyStatService{}).(*services.ServerHTTPFirewallDailyStatService)
var instance = this.serviceInstance(&services.ServerHTTPFirewallDailyStatService{}).(*services.ServerHTTPFirewallDailyStatService)
pb.RegisterServerHTTPFirewallDailyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.DNSTaskService{}).(*services.DNSTaskService)
var instance = this.serviceInstance(&services.DNSTaskService{}).(*services.DNSTaskService)
pb.RegisterDNSTaskServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeClusterFirewallActionService{}).(*services.NodeClusterFirewallActionService)
var instance = this.serviceInstance(&services.NodeClusterFirewallActionService{}).(*services.NodeClusterFirewallActionService)
pb.RegisterNodeClusterFirewallActionServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MonitorNodeService{}).(*services.MonitorNodeService)
var instance = this.serviceInstance(&services.MonitorNodeService{}).(*services.MonitorNodeService)
pb.RegisterMonitorNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.AuthorityNodeService{}).(*services.AuthorityNodeService)
var instance = this.serviceInstance(&services.AuthorityNodeService{}).(*services.AuthorityNodeService)
pb.RegisterAuthorityNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.LatestItemService{}).(*services.LatestItemService)
var instance = this.serviceInstance(&services.LatestItemService{}).(*services.LatestItemService)
pb.RegisterLatestItemServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeThresholdService{}).(*services.NodeThresholdService)
var instance = this.serviceInstance(&services.NodeThresholdService{}).(*services.NodeThresholdService)
pb.RegisterNodeThresholdServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPFastcgiService{}).(*services.HTTPFastcgiService)
var instance = this.serviceInstance(&services.HTTPFastcgiService{}).(*services.HTTPFastcgiService)
pb.RegisterHTTPFastcgiServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSClusterService{}).(*nameservers.NSClusterService)
var instance = this.serviceInstance(&nameservers.NSClusterService{}).(*nameservers.NSClusterService)
pb.RegisterNSClusterServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSNodeService{}).(*nameservers.NSNodeService)
var instance = this.serviceInstance(&nameservers.NSNodeService{}).(*nameservers.NSNodeService)
pb.RegisterNSNodeServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSDomainService{}).(*nameservers.NSDomainService)
var instance = this.serviceInstance(&nameservers.NSDomainService{}).(*nameservers.NSDomainService)
pb.RegisterNSDomainServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSRecordService{}).(*nameservers.NSRecordService)
var instance = this.serviceInstance(&nameservers.NSRecordService{}).(*nameservers.NSRecordService)
pb.RegisterNSRecordServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSRouteService{}).(*nameservers.NSRouteService)
var instance = this.serviceInstance(&nameservers.NSRouteService{}).(*nameservers.NSRouteService)
pb.RegisterNSRouteServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSKeyService{}).(*nameservers.NSKeyService)
var instance = this.serviceInstance(&nameservers.NSKeyService{}).(*nameservers.NSKeyService)
pb.RegisterNSKeyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSAccessLogService{}).(*nameservers.NSAccessLogService)
var instance = this.serviceInstance(&nameservers.NSAccessLogService{}).(*nameservers.NSAccessLogService)
pb.RegisterNSAccessLogServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSRecordHourlyStatService{}).(*nameservers.NSRecordHourlyStatService)
var instance = this.serviceInstance(&nameservers.NSRecordHourlyStatService{}).(*nameservers.NSRecordHourlyStatService)
pb.RegisterNSRecordHourlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSQuestionOptionService{}).(*nameservers.NSQuestionOptionService)
var instance = this.serviceInstance(&nameservers.NSQuestionOptionService{}).(*nameservers.NSQuestionOptionService)
pb.RegisterNSQuestionOptionServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&nameservers.NSService{}).(*nameservers.NSService)
var instance = this.serviceInstance(&nameservers.NSService{}).(*nameservers.NSService)
pb.RegisterNSServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.HTTPAuthPolicyService{}).(*services.HTTPAuthPolicyService)
var instance = this.serviceInstance(&services.HTTPAuthPolicyService{}).(*services.HTTPAuthPolicyService)
pb.RegisterHTTPAuthPolicyServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MetricItemService{}).(*services.MetricItemService)
var instance = this.serviceInstance(&services.MetricItemService{}).(*services.MetricItemService)
pb.RegisterMetricItemServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.NodeClusterMetricItemService{}).(*services.NodeClusterMetricItemService)
var instance = this.serviceInstance(&services.NodeClusterMetricItemService{}).(*services.NodeClusterMetricItemService)
pb.RegisterNodeClusterMetricItemServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MetricStatService{}).(*services.MetricStatService)
var instance = this.serviceInstance(&services.MetricStatService{}).(*services.MetricStatService)
pb.RegisterMetricStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.MetricChartService{}).(*services.MetricChartService)
var instance = this.serviceInstance(&services.MetricChartService{}).(*services.MetricChartService)
pb.RegisterMetricChartServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerStatBoardService{}).(*services.ServerStatBoardService)
var instance = this.serviceInstance(&services.ServerStatBoardService{}).(*services.ServerStatBoardService)
pb.RegisterServerStatBoardServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerStatBoardChartService{}).(*services.ServerStatBoardChartService)
var instance = this.serviceInstance(&services.ServerStatBoardChartService{}).(*services.ServerStatBoardChartService)
pb.RegisterServerStatBoardChartServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.PlanService{}).(*services.PlanService)
var instance = this.serviceInstance(&services.PlanService{}).(*services.PlanService)
pb.RegisterPlanServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.UserPlanService{}).(*services.UserPlanService)
var instance = this.serviceInstance(&services.UserPlanService{}).(*services.UserPlanService)
pb.RegisterUserPlanServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.ServerDomainHourlyStatService{}).(*services.ServerDomainHourlyStatService)
var instance = this.serviceInstance(&services.ServerDomainHourlyStatService{}).(*services.ServerDomainHourlyStatService)
pb.RegisterServerDomainHourlyStatServiceServer(server, instance)
this.rest(instance)
}
{
instance := this.serviceInstance(&services.TrafficDailyStatService{}).(*services.TrafficDailyStatService)
var instance = this.serviceInstance(&services.TrafficDailyStatService{}).(*services.TrafficDailyStatService)
pb.RegisterTrafficDailyStatServiceServer(server, 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)
// TODO check service names
for serviceName := range server.GetServiceInfo() {
index := strings.LastIndex(serviceName, ".")
var index = strings.LastIndex(serviceName, ".")
if index >= 0 {
serviceName = serviceName[index+1:]
}
@@ -590,7 +613,7 @@ func (this *APINode) rest(instance interface{}) {
defer this.serviceInstanceLocker.Unlock()
var name = reflect.TypeOf(instance).String()
index := strings.LastIndex(name, ".")
var index = strings.LastIndex(name, ".")
if index >= 0 {
name = name[index+1:]
}
@@ -606,7 +629,7 @@ func (this *APINode) serviceInstance(instance interface{}) interface{} {
this.serviceInstanceLocker.Lock()
defer this.serviceInstanceLocker.Unlock()
typeName := reflect.TypeOf(instance).String()
var typeName = reflect.TypeOf(instance).String()
result, ok := this.serviceInstanceMap[typeName]
if ok {
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"
"io"
"path/filepath"
"time"
)
// 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")
}
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 {
return nil, err
}
@@ -452,12 +462,12 @@ func (this *NSNodeService) CheckNSNodeLatestVersion(ctx context.Context, req *pb
// DownloadNSNodeInstallationFile 下载最新DNS节点安装文件
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 {
return nil, err
}
file := installers.SharedDeployManager.FindNSNodeFile(req.Os, req.Arch)
var file = installers.SharedDeployManager.FindNSNodeFile(req.Os, req.Arch)
if file == nil {
return &pb.DownloadNSNodeInstallationFileResponse{}, nil
}
@@ -472,6 +482,9 @@ func (this *NSNodeService) DownloadNSNodeInstallationFile(ctx context.Context, r
return nil, err
}
// 增加下载速度监控
installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleDNS, nodeId, int64(len(data)))
return &pb.DownloadNSNodeInstallationFileResponse{
Sum: sum,
Offset: offset,

View File

@@ -2,11 +2,14 @@ package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"google.golang.org/grpc/metadata"
"time"
)
type AuthorityNodeService struct {
@@ -223,9 +226,18 @@ func (this *AuthorityNodeService) UpdateAuthorityNodeStatus(ctx context.Context,
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 {
return nil, err
}

View File

@@ -59,7 +59,7 @@ func (this *DNSProviderService) CountAllEnabledDNSProviders(ctx context.Context,
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 {
return nil, err
}
@@ -76,9 +76,9 @@ func (this *DNSProviderService) ListEnabledDNSProviders(ctx context.Context, req
// 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 {
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
}
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
var templatePolicy = firewallconfigs.HTTPFirewallTemplate()
tx := this.NullTx()
@@ -186,18 +186,18 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
return nil, errors.New("can not found firewall policy")
}
inboundConfig := firewallPolicy.Inbound
var inboundConfig = firewallPolicy.Inbound
if inboundConfig == nil {
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
}
outboundConfig := firewallPolicy.Outbound
var outboundConfig = firewallPolicy.Outbound
if outboundConfig == nil {
outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
}
// 更新老的
oldCodes := []string{}
var oldCodes = []string{}
if firewallPolicy.Inbound != nil {
for _, g := range firewallPolicy.Inbound.Groups {
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 {
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
}
tx := this.NullTx()
var tx = this.NullTx()
if userId > 0 {
listId, err := models.SharedIPItemDAO.FindItemListId(tx, req.IpItemId)
if err != nil {
return nil, err
// 如果是使用IPItemId删除
if req.IpItemId > 0 {
if userId > 0 {
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 {
return nil, err
}
}
err = models.SharedIPItemDAO.DisableIPItem(tx, req.IpItemId)
if err != nil {
return nil, err
// 如果是使用ipFrom+ipTo删除
if len(req.IpFrom) > 0 {
// 检查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()

View File

@@ -21,9 +21,20 @@ func (this *IPListService) CreateIPList(ctx context.Context, req *pb.CreateIPLis
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 {
return nil, err
}
@@ -50,12 +61,18 @@ func (this *IPListService) UpdateIPList(ctx context.Context, req *pb.UpdateIPLis
// FindEnabledIPList 查找IP列表
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 {
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)
if err != nil {

View File

@@ -5,10 +5,81 @@ package services
import (
"context"
"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/iwind/TeaGo/dbs"
"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 指标统计数据相关服务
type MetricStatService struct {
BaseService
@@ -27,24 +98,18 @@ func (this *MetricStatService) UploadMetricStats(ctx context.Context, req *pb.Up
return nil, err
}
// 删除旧的数据
err = models.SharedMetricStatDAO.DeleteNodeItemStats(tx, nodeId, req.ServerId, req.ItemId, req.Time)
if err != nil {
return nil, err
var key = types.String(clusterId) + "@" + types.String(nodeId) + "@" + types.String(req.ServerId) + "@" + types.String(req.ItemId)
metricStatsLocker.Lock()
metricStatsMap[key] = req
select {
case metricStatKeysQueue <- key:
default:
// 如果满了就删除
delete(metricStatsMap, key)
}
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 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
}
metricStatsLocker.Unlock()
return this.Success()
}

View File

@@ -10,17 +10,18 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/installers"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/andybalholm/brotli"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
"io"
@@ -399,7 +400,7 @@ func (this *NodeService) FindAllEnabledNodesWithNodeClusterId(ctx context.Contex
tx := this.NullTx()
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId)
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(tx, req.NodeClusterId, req.IncludeSecondary)
if err != nil {
return nil, err
}
@@ -767,13 +768,14 @@ func (this *NodeService) FindCurrentNodeConfig(ctx context.Context, req *pb.Find
NodeJSON: data,
DataSize: int64(len(data)),
IsCompressed: isCompressed,
Timestamp: time.Now().Unix(),
}, nil
}
// UpdateNodeStatus 更新节点状态
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 {
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")
}
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 {
return nil, err
}
@@ -823,7 +834,7 @@ func (this *NodeService) InstallNode(ctx context.Context, req *pb.InstallNodeReq
goman.New(func() {
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, false)
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() {
err = installers.SharedNodeQueue().InstallNodeProcess(req.NodeId, true)
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 下载最新边缘节点安装文件
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 {
return nil, err
}
file := installers.SharedDeployManager.FindNodeFile(req.Os, req.Arch)
var file = installers.SharedDeployManager.FindNodeFile(req.Os, req.Arch)
if file == nil {
return &pb.DownloadNodeInstallationFileResponse{}, nil
}
@@ -1611,6 +1622,9 @@ func (this *NodeService) DownloadNodeInstallationFile(ctx context.Context, req *
return nil, err
}
// 增加下载速度监控
installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleNode, nodeId, int64(len(data)))
return &pb.DownloadNodeInstallationFileResponse{
Sum: sum,
Offset: offset,
@@ -1746,3 +1760,204 @@ func (this *NodeService) FindNodeLevelInfo(ctx context.Context, req *pb.FindNode
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/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
@@ -83,7 +84,7 @@ func (this *NodeClusterService) UpdateNodeCluster(ctx context.Context, req *pb.U
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 {
return nil, err
}
@@ -148,22 +149,21 @@ func (this *NodeClusterService) FindEnabledNodeCluster(ctx context.Context, req
}
return &pb.FindEnabledNodeClusterResponse{NodeCluster: &pb.NodeCluster{
Id: int64(cluster.Id),
Name: cluster.Name,
CreatedAt: int64(cluster.CreatedAt),
InstallDir: cluster.InstallDir,
NodeGrantId: int64(cluster.GrantId),
UniqueId: cluster.UniqueId,
Secret: cluster.Secret,
HttpCachePolicyId: int64(cluster.CachePolicyId),
HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId),
DnsName: cluster.DnsName,
DnsDomainId: int64(cluster.DnsDomainId),
IsOn: cluster.IsOn,
TimeZone: cluster.TimeZone,
NodeMaxThreads: int32(cluster.NodeMaxThreads),
NodeTCPMaxConnections: int32(cluster.NodeTCPMaxConnections),
AutoOpenPorts: cluster.AutoOpenPorts == 1,
Id: int64(cluster.Id),
Name: cluster.Name,
CreatedAt: int64(cluster.CreatedAt),
InstallDir: cluster.InstallDir,
NodeGrantId: int64(cluster.GrantId),
UniqueId: cluster.UniqueId,
Secret: cluster.Secret,
HttpCachePolicyId: int64(cluster.CachePolicyId),
HttpFirewallPolicyId: int64(cluster.HttpFirewallPolicyId),
DnsName: cluster.DnsName,
DnsDomainId: int64(cluster.DnsDomainId),
IsOn: cluster.IsOn,
TimeZone: cluster.TimeZone,
NodeMaxThreads: int32(cluster.NodeMaxThreads),
AutoOpenPorts: cluster.AutoOpenPorts == 1,
}}, nil
}
@@ -429,7 +429,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
dnsInfo, err := models.SharedNodeClusterDAO.FindClusterDNSInfo(tx, req.NodeClusterId, nil)
if err != nil {
@@ -457,6 +457,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
}, nil
}
@@ -471,7 +472,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
Provider: nil,
}, nil
}
pbDomain := &pb.DNSDomain{
var pbDomain = &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn,
@@ -515,6 +516,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
DefaultRoute: defaultRoute,
}, nil
}
@@ -527,7 +529,7 @@ func (this *NodeClusterService) CountAllEnabledNodeClustersWithDNSProviderId(ctx
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSProviderId(tx, req.DnsProviderId)
if err != nil {
@@ -544,7 +546,7 @@ func (this *NodeClusterService) CountAllEnabledNodeClustersWithDNSDomainId(ctx c
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
count, err := models.SharedNodeClusterDAO.CountAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId)
if err != nil {
@@ -561,7 +563,7 @@ func (this *NodeClusterService) FindAllEnabledNodeClustersWithDNSDomainId(ctx co
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(tx, req.DnsDomainId)
if err != nil {
@@ -589,7 +591,7 @@ func (this *NodeClusterService) CheckNodeClusterDNSName(ctx context.Context, req
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
exists, err := models.SharedNodeClusterDAO.ExistClusterDNSName(tx, req.DnsName, req.NodeClusterId)
if err != nil {
@@ -606,9 +608,9 @@ func (this *NodeClusterService) UpdateNodeClusterDNS(ctx context.Context, req *p
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 {
return nil, err
}
@@ -1040,6 +1042,18 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
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
if models.IsNotNull(cluster.SystemServices) {
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
}
@@ -1101,16 +1118,116 @@ func (this *NodeClusterService) UpdateNodeClusterWebPPolicy(ctx context.Context,
return nil, err
}
var tx = this.NullTx()
var webpPolicy = &nodeconfigs.WebPImagePolicy{}
err = json.Unmarshal(req.WebpPolicyJSON, webpPolicy)
if err != nil {
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)
if err != nil {
return nil, err
}
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
}
pbTasks := []*pb.NodeTask{}
var pbTasks = []*pb.NodeTask{}
for _, task := range tasks {
pbTasks = append(pbTasks, &pb.NodeTask{
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)
if err != nil {
return nil, err
}
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 stringutil.VersionCompare(deployFile.Version, status.BuildVersion) > 0 {
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 {
return nil, err
}
@@ -87,20 +87,23 @@ func (this *OriginService) UpdateOrigin(ctx context.Context, req *pb.UpdateOrigi
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
// TODO 校验权限
err = models.SharedOriginDAO.CheckUserOrigin(tx, userId, req.OriginId)
if err != nil {
return nil, err
}
}
if req.Addr == nil {
return nil, errors.New("'addr' can not be nil")
}
addrMap := maps.Map{
var addrMap = maps.Map{
"protocol": req.Addr.Protocol,
"portRange": req.Addr.PortRange,
"host": req.Addr.Host,
}
tx := this.NullTx()
// 校验参数
var connTimeout = &shared.TimeDuration{}
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 {
return nil, err
}
@@ -154,11 +157,14 @@ func (this *OriginService) FindEnabledOrigin(ctx context.Context, req *pb.FindEn
return nil, err
}
if userId > 0 {
// TODO 校验权限
}
var tx = this.NullTx()
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)
if err != nil {
@@ -196,11 +202,14 @@ func (this *OriginService) FindEnabledOriginConfig(ctx context.Context, req *pb.
return nil, err
}
if userId > 0 {
// TODO 校验权限
}
var tx = this.NullTx()
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)
if err != nil {

View File

@@ -27,12 +27,39 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
}
var pbCities = []*pb.RegionCity{}
var provincesMap = map[int64]*regions.RegionProvince{} // provinceId => RegionProvince
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{
Id: int64(city.Id),
Name: city.Name,
Codes: city.DecodeCodes(),
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)
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{}
@@ -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 {
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/regions"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"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 {
return nil, err
}
@@ -193,6 +192,56 @@ func (this *ServerService) UpdateServerBasic(ctx context.Context, req *pb.Update
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 修改服务是否启用
func (this *ServerService) UpdateServerIsOn(ctx context.Context, req *pb.UpdateServerIsOnRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
@@ -200,7 +249,7 @@ func (this *ServerService) UpdateServerIsOn(ctx context.Context, req *pb.UpdateS
return nil, err
}
tx := this.NullTx()
var tx = this.NullTx()
if userId > 0 {
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
@@ -833,8 +882,9 @@ func (this *ServerService) FindEnabledServer(ctx context.Context, req *pb.FindEn
continue
}
pbGroups = append(pbGroups, &pb.ServerGroup{
Id: int64(group.Id),
Name: group.Name,
Id: int64(group.Id),
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 {
return &pb.PurgeServerCacheResponse{IsOk: true}, nil
}
var tx = this.NullTx()
var cacheMap = utils.NewCacheMap()
var purgeResponse = &pb.PurgeServerCacheResponse{}
for _, domain := range req.Domains {
servers, err := models.SharedServerDAO.FindAllEnabledServersWithDomain(tx, domain)
var tx = this.NullTx()
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 {
return nil, err
}
for _, server := range servers {
clusterId := int64(server.ClusterId)
if clusterId > 0 {
nodeIds, err := models.SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId)
if err != nil {
return nil, err
}
var countKeys = 0
cachePolicyId, err := models.SharedNodeClusterDAO.FindClusterHTTPCachePolicyId(tx, clusterId, cacheMap)
if err != nil {
return nil, err
}
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
}
}
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
}
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,
User: nil,
Plan: &pb.Plan{
Id: int64(plan.Id),
Name: plan.Name,
PriceType: plan.PriceType,
Id: int64(plan.Id),
Name: plan.Name,
PriceType: plan.PriceType,
TrafficPriceJSON: plan.TrafficPrice,
TrafficLimitJSON: plan.TrafficLimit,
},
},
}, nil

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