Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d03455e3b0 | ||
|
|
af1cb14110 | ||
|
|
0feffa755e | ||
|
|
7cfbe2e473 | ||
|
|
7f63dc4565 | ||
|
|
e90424f80a | ||
|
|
6271125296 | ||
|
|
44ac4b83c5 | ||
|
|
c75e2c55c6 | ||
|
|
51a3029c09 | ||
|
|
580341d397 | ||
|
|
fb4bad0731 | ||
|
|
70efff2e6b | ||
|
|
97c76ef22f | ||
|
|
e763095756 | ||
|
|
b7dc2738e2 | ||
|
|
3db826b578 | ||
|
|
dc8975e374 | ||
|
|
c0cbd7c607 | ||
|
|
4d9f404bb0 | ||
|
|
06bb61804b |
@@ -115,7 +115,11 @@ function build() {
|
||||
fi
|
||||
|
||||
# building api node
|
||||
env GOOS="$OS" GOARCH="$ARCH" go build -trimpath -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/$NAME" "$ROOT"/../cmd/edge-api/main.go
|
||||
if [ ! -f "${DIST}/bin/${NAME}" ]; then
|
||||
echo "build failed!"
|
||||
exit
|
||||
fi
|
||||
|
||||
# delete hidden files
|
||||
find "$DIST" -name ".DS_Store" -delete
|
||||
|
||||
2
cmd/edge-instance-installer/.gitignore
vendored
Normal file
2
cmd/edge-instance-installer/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
edge-instance-installer*
|
||||
prepare.sh
|
||||
45
cmd/edge-instance-installer/build.sh
Executable file
45
cmd/edge-instance-installer/build.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function build() {
|
||||
ROOT=$(dirname "$0")
|
||||
|
||||
OS="${1}"
|
||||
ARCH="${2}"
|
||||
TAG="${3}"
|
||||
|
||||
if [ -z "$OS" ]; then
|
||||
echo "usage: build.sh OS ARCH"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
echo "usage: build.sh OS ARCH"
|
||||
exit
|
||||
fi
|
||||
|
||||
VERSION=$(lookup_version "${ROOT}/../../internal/const/const.go")
|
||||
TARGET_NAME="edge-instance-installer-${OS}-${ARCH}-v${VERSION}"
|
||||
|
||||
env GOOS=linux GOARCH="${ARCH}" go build -tags="${TAG}" -trimpath -ldflags="-s -w" -o "${TARGET_NAME}" main.go
|
||||
|
||||
if [ -f "${TARGET_NAME}" ]; then
|
||||
cp "${TARGET_NAME}" "${ROOT}/../../../EdgeAdmin/docker/instance/edge-instance/assets"
|
||||
fi
|
||||
|
||||
echo "[done]"
|
||||
}
|
||||
|
||||
function lookup_version() {
|
||||
FILE=$1
|
||||
VERSION_DATA=$(cat "$FILE")
|
||||
re="Version[ ]+=[ ]+\"([0-9.]+)\""
|
||||
if [[ $VERSION_DATA =~ $re ]]; then
|
||||
VERSION=${BASH_REMATCH[1]}
|
||||
echo "$VERSION"
|
||||
else
|
||||
echo "could not match version"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
build "$1" "$2" "$3"
|
||||
97
cmd/edge-instance-installer/main.go
Normal file
97
cmd/edge-instance-installer/main.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/instances"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var verbose = lists.ContainsString(os.Args, "-v")
|
||||
|
||||
var dbHost = "127.0.0.1"
|
||||
var dbPassword = "123456"
|
||||
var dbName = "edges"
|
||||
|
||||
envDBHost, _ := os.LookupEnv("EDGE_DB_HOST")
|
||||
if len(envDBHost) > 0 {
|
||||
dbHost = envDBHost
|
||||
if verbose {
|
||||
log.Println("env EDGE_DB_HOST=" + envDBHost)
|
||||
}
|
||||
}
|
||||
|
||||
envDBPassword, _ := os.LookupEnv("EDGE_DB_PASSWORD")
|
||||
if len(envDBPassword) > 0 {
|
||||
dbPassword = envDBPassword
|
||||
if verbose {
|
||||
log.Println("env EDGE_DB_PASSWORD=" + envDBPassword)
|
||||
}
|
||||
}
|
||||
|
||||
envDBName, _ := os.LookupEnv("EDGE_DB_NAME")
|
||||
if len(envDBName) > 0 {
|
||||
dbName = envDBName
|
||||
if verbose {
|
||||
log.Println("env EDGE_DB_NAME=" + envDBName)
|
||||
}
|
||||
}
|
||||
|
||||
var isTesting = lists.ContainsString(os.Args, "-test") || lists.ContainsString(os.Args, "--test")
|
||||
if isTesting {
|
||||
fmt.Println("testing mode ...")
|
||||
}
|
||||
|
||||
var instance = instances.NewInstance(instances.Options{
|
||||
IsTesting: isTesting,
|
||||
Verbose: verbose,
|
||||
Cacheable: false,
|
||||
WorkDir: "",
|
||||
SrcDir: "/usr/local/goedge/src",
|
||||
DB: struct {
|
||||
Host string
|
||||
Port int
|
||||
Username string
|
||||
Password string
|
||||
Name string
|
||||
}{
|
||||
Host: dbHost,
|
||||
Port: 3306,
|
||||
Username: "root",
|
||||
Password: dbPassword,
|
||||
Name: dbName,
|
||||
},
|
||||
AdminNode: struct {
|
||||
Port int
|
||||
}{
|
||||
Port: 7788,
|
||||
},
|
||||
APINode: struct {
|
||||
HTTPPort int
|
||||
RestHTTPPort int
|
||||
}{
|
||||
HTTPPort: 8001,
|
||||
RestHTTPPort: 8002,
|
||||
},
|
||||
Node: struct{ HTTPPort int }{
|
||||
HTTPPort: 80,
|
||||
},
|
||||
UserNode: struct {
|
||||
HTTPPort int
|
||||
}{
|
||||
HTTPPort: 7799,
|
||||
},
|
||||
})
|
||||
err := instance.SetupAll()
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]setup failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "1.3.3"
|
||||
Version = "1.3.4"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -20,7 +20,7 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "1.3.3"
|
||||
NodeVersion = "1.3.4"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
SQLVersion = "11"
|
||||
|
||||
@@ -130,6 +130,19 @@ func (this *AdminDAO) FindAdminIdWithUsername(tx *dbs.Tx, username string) (int6
|
||||
return int64(one.(*Admin).Id), nil
|
||||
}
|
||||
|
||||
// FindAdminWithUsername 根据用户名查询管理员信息
|
||||
func (this *AdminDAO) FindAdminWithUsername(tx *dbs.Tx, username string) (*Admin, error) {
|
||||
one, err := this.Query(tx).
|
||||
Attr("username", username).
|
||||
State(AdminStateEnabled).
|
||||
ResultPk().
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
return one.(*Admin), nil
|
||||
}
|
||||
|
||||
// UpdateAdminPassword 更改管理员密码
|
||||
func (this *AdminDAO) UpdateAdminPassword(tx *dbs.Tx, adminId int64, password string) error {
|
||||
if adminId <= 0 {
|
||||
@@ -212,7 +225,7 @@ func (this *AdminDAO) UpdateAdmin(tx *dbs.Tx, adminId int64, username string, ca
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckAdminUsername 检查用户名是否存在
|
||||
// CheckAdminUsername 检查管理员用户名是否存在
|
||||
func (this *AdminDAO) CheckAdminUsername(tx *dbs.Tx, adminId int64, username string) (bool, error) {
|
||||
query := this.Query(tx).
|
||||
State(AdminStateEnabled).
|
||||
|
||||
@@ -1466,7 +1466,7 @@ func (this *HTTPWebDAO) UpdateWebReferers(tx *dbs.Tx, webId int64, referersConfi
|
||||
return this.NotifyUpdate(tx, webId)
|
||||
}
|
||||
|
||||
// FindWebReferers 查找服务的防盗链配置
|
||||
// FindWebReferers 查找网站的防盗链配置
|
||||
func (this *HTTPWebDAO) FindWebReferers(tx *dbs.Tx, webId int64) ([]byte, error) {
|
||||
return this.Query(tx).
|
||||
Pk(webId).
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -449,6 +450,14 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
||||
for _, province := range dbProvinces {
|
||||
for _, code := range province.AllCodes() {
|
||||
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.ValueId)
|
||||
|
||||
for _, suffix := range regions.RegionProvinceSuffixes {
|
||||
if strings.HasSuffix(code, suffix) {
|
||||
provinceMap[types.String(province.CountryId)+"_"+strings.TrimSuffix(code, suffix)] = int64(province.ValueId)
|
||||
} else {
|
||||
provinceMap[types.String(province.CountryId)+"_"+(code+suffix)] = int64(province.ValueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,40 +135,16 @@ func (this *LoginSessionDAO) WriteSessionValue(tx *dbs.Tx, sid string, key strin
|
||||
sessionOp.UserId = userId
|
||||
|
||||
if isNewSession {
|
||||
// 删除此用户之前创建的SESSION,防止单个用户SESSION过多
|
||||
// TODO 将来改成按照活跃时间排序
|
||||
const maxSessionsPerUser = 10
|
||||
oldOnes, err := this.Query(tx).
|
||||
// 删除此用户之前创建的SESSION,不再保存以往的SESSION,避免安全问题
|
||||
err = this.Query(tx).
|
||||
ResultPk().
|
||||
Attr("adminId", adminId).
|
||||
Attr("userId", userId).
|
||||
Asc("createdAt").
|
||||
FindAll()
|
||||
Neq("sid", sid).
|
||||
DeleteQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var countOldOnes = len(oldOnes)
|
||||
if countOldOnes > maxSessionsPerUser {
|
||||
var countDeleted int
|
||||
for _, oldOne := range oldOnes {
|
||||
var oldSessionId = int64(oldOne.(*LoginSession).Id)
|
||||
if oldSessionId == sessionId {
|
||||
continue
|
||||
}
|
||||
|
||||
if countDeleted < countOldOnes-maxSessionsPerUser {
|
||||
err = this.Query(tx).
|
||||
Pk(oldSessionId).
|
||||
DeleteQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
countDeleted++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ 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"
|
||||
@@ -759,10 +758,5 @@ func (this *MetricStatDAO) canIgnore(err error) bool {
|
||||
}
|
||||
|
||||
// 忽略 Error 1213: Deadlock found 错误
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1213 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return CheckSQLErrCode(err, 1213)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ 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"
|
||||
@@ -289,10 +288,5 @@ func (this *MetricSumStatDAO) canIgnore(err error) bool {
|
||||
}
|
||||
|
||||
// 忽略 Error 1213: Deadlock found 错误
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1213 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return CheckSQLErrCode(err, 1213)
|
||||
}
|
||||
|
||||
@@ -98,6 +98,14 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// FindRegionCountryRouteCode 查找国家|地区线路代号
|
||||
func (this *RegionCountryDAO) FindRegionCountryRouteCode(tx *dbs.Tx, countryId int64) (string, error) {
|
||||
return this.Query(tx).
|
||||
Attr("valueId", countryId).
|
||||
Result("routeCode").
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindCountryIdWithDataId 根据数据ID查找国家
|
||||
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
|
||||
@@ -14,11 +14,12 @@ const (
|
||||
RegionCountryField_DataId dbs.FieldName = "dataId" // 原始数据ID
|
||||
RegionCountryField_Pinyin dbs.FieldName = "pinyin" // 拼音
|
||||
RegionCountryField_IsCommon dbs.FieldName = "isCommon" // 是否常用
|
||||
RegionCountryField_RouteCode dbs.FieldName = "routeCode" // 线路代号
|
||||
)
|
||||
|
||||
// RegionCountry 区域-国家/地区
|
||||
type RegionCountry struct {
|
||||
Id1 uint32 `field:"id"` // ID
|
||||
Id uint32 `field:"id"` // ID
|
||||
ValueId uint32 `field:"valueId"` // 实际ID
|
||||
ValueCode string `field:"valueCode"` // 值代号
|
||||
Name string `field:"name"` // 名称
|
||||
@@ -29,6 +30,7 @@ type RegionCountry struct {
|
||||
DataId string `field:"dataId"` // 原始数据ID
|
||||
Pinyin dbs.JSON `field:"pinyin"` // 拼音
|
||||
IsCommon bool `field:"isCommon"` // 是否常用
|
||||
RouteCode string `field:"routeCode"` // 线路代号
|
||||
}
|
||||
|
||||
type RegionCountryOperator struct {
|
||||
@@ -43,6 +45,7 @@ type RegionCountryOperator struct {
|
||||
DataId any // 原始数据ID
|
||||
Pinyin any // 拼音
|
||||
IsCommon any // 是否常用
|
||||
RouteCode any // 线路代号
|
||||
}
|
||||
|
||||
func NewRegionCountryOperator() *RegionCountryOperator {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,6 +19,8 @@ const (
|
||||
RegionProvinceStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
var RegionProvinceSuffixes = []string{"省", "州", "区", "大区", "特区", "港", "岛", "环礁", "谷地", "山", "口岸", "郡", "县", "城", "河", "河畔", "市"}
|
||||
|
||||
type RegionProvinceDAO dbs.DAO
|
||||
|
||||
func NewRegionProvinceDAO() *RegionProvinceDAO {
|
||||
@@ -77,6 +80,14 @@ func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (str
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindRegionCountryId 获取省份对应的国家|地区
|
||||
func (this *RegionProvinceDAO) FindRegionCountryId(tx *dbs.Tx, provinceId int64) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("valueId", provinceId).
|
||||
Result("countryId").
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// FindProvinceIdWithDataId 根据数据ID查找省份
|
||||
func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
@@ -87,6 +98,37 @@ func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId strin
|
||||
|
||||
// FindProvinceIdWithName 根据省份名查找省份ID
|
||||
func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
|
||||
{
|
||||
provinceId, err := this.findProvinceIdWithExactName(tx, countryId, provinceName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if provinceId > 0 {
|
||||
return provinceId, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 候选词
|
||||
for _, suffix := range RegionProvinceSuffixes {
|
||||
var name string
|
||||
if strings.HasSuffix(provinceName, suffix) {
|
||||
name = strings.TrimSuffix(provinceName, suffix)
|
||||
} else {
|
||||
name = provinceName + suffix
|
||||
}
|
||||
provinceId, err := this.findProvinceIdWithExactName(tx, countryId, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if provinceId > 0 {
|
||||
return provinceId, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (this *RegionProvinceDAO) findProvinceIdWithExactName(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("countryId", countryId).
|
||||
Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))").
|
||||
|
||||
@@ -26,6 +26,25 @@ func TestRegionProvinceDAO_FindProvinceIdWithName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegionProvinceDAO_FindProvinceIdWithName_Suffix(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
for _, name := range []string{
|
||||
"维埃纳",
|
||||
"维埃纳省",
|
||||
"维埃纳大区",
|
||||
"维埃纳市",
|
||||
"维埃纳小区", // expect 0
|
||||
} {
|
||||
provinceId, err := SharedRegionProvinceDAO.FindProvinceIdWithName(tx, 74, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(name, "=>", provinceId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegionProvinceDAO_FindSimilarProvinces(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
|
||||
@@ -12,11 +12,12 @@ const (
|
||||
RegionProvinceField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
|
||||
RegionProvinceField_State dbs.FieldName = "state" // 状态
|
||||
RegionProvinceField_DataId dbs.FieldName = "dataId" // 原始数据ID
|
||||
RegionProvinceField_RouteCode dbs.FieldName = "routeCode" // 线路代号
|
||||
)
|
||||
|
||||
// RegionProvince 区域-省份
|
||||
type RegionProvince struct {
|
||||
Id1 uint32 `field:"id"` // ID
|
||||
Id uint32 `field:"id"` // ID
|
||||
ValueId uint32 `field:"valueId"` // 实际ID
|
||||
CountryId uint32 `field:"countryId"` // 国家ID
|
||||
Name string `field:"name"` // 名称
|
||||
@@ -25,6 +26,7 @@ type RegionProvince struct {
|
||||
CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
DataId string `field:"dataId"` // 原始数据ID
|
||||
RouteCode string `field:"routeCode"` // 线路代号
|
||||
}
|
||||
|
||||
type RegionProvinceOperator struct {
|
||||
@@ -37,6 +39,7 @@ type RegionProvinceOperator struct {
|
||||
CustomCodes any // 自定义代号
|
||||
State any // 状态
|
||||
DataId any // 原始数据ID
|
||||
RouteCode any // 线路代号
|
||||
}
|
||||
|
||||
func NewRegionProvinceOperator() *RegionProvinceOperator {
|
||||
|
||||
@@ -177,10 +177,10 @@ func (this *SysSettingDAO) ReadUserUIConfig(tx *dbs.Tx) (*systemconfigs.UserUICo
|
||||
return nil, err
|
||||
}
|
||||
if len(valueJSON) == 0 {
|
||||
return systemconfigs.DefaultUserUIConfig(), nil
|
||||
return systemconfigs.NewUserUIConfig(), nil
|
||||
}
|
||||
|
||||
var config = systemconfigs.DefaultUserUIConfig()
|
||||
var config = systemconfigs.NewUserUIConfig()
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
@@ -60,8 +61,8 @@ func CheckSQLErrCode(err error, code uint16) bool {
|
||||
}
|
||||
|
||||
// 快速判断错误方法
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == code { // Error 1050: Table 'xxx' already exists
|
||||
var mysqlErr *mysql.MySQLError
|
||||
if errors.As(err, &mysqlErr) && mysqlErr.Number == code { // Error 1050: Table 'xxx' already exists
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -86,6 +87,6 @@ func IsMySQLError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(*mysql.MySQLError)
|
||||
return ok
|
||||
var mysqlErr *mysql.MySQLError
|
||||
return errors.As(err, &mysqlErr)
|
||||
}
|
||||
|
||||
39
internal/db/models/utils_test.go
Normal file
39
internal/db/models/utils_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsMySQLError(t *testing.T) {
|
||||
var a = assert.NewAssertion(t)
|
||||
|
||||
{
|
||||
var err error
|
||||
a.IsFalse(models.IsMySQLError(err))
|
||||
}
|
||||
|
||||
{
|
||||
var err = errors.New("hello")
|
||||
a.IsFalse(models.IsMySQLError(err))
|
||||
}
|
||||
|
||||
{
|
||||
db, err := dbs.Default()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
_, err = db.Exec("SELECT abc")
|
||||
a.IsTrue(models.IsMySQLError(err))
|
||||
a.IsTrue(models.CheckSQLErrCode(err, 1054))
|
||||
a.IsFalse(models.CheckSQLErrCode(err, 1000))
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,14 @@ func (this *AliDNSProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *AliDNSProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
params["accessKeySecret"] = MaskString(params.GetString("accessKeySecret"))
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *AliDNSProvider) GetDomains() (domains []string, err error) {
|
||||
var pageNumber = 1
|
||||
|
||||
@@ -66,6 +66,14 @@ func (this *CloudFlareProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *CloudFlareProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
params["apiKey"] = MaskString(params.GetString("apiKey"))
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *CloudFlareProvider) GetDomains() (domains []string, err error) {
|
||||
for page := 1; page <= 500; page++ {
|
||||
|
||||
@@ -53,6 +53,11 @@ func (this *CustomHTTPProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *CustomHTTPProvider) MaskParams(params maps.Map) {
|
||||
// 这里暂时不要掩码,避免用户忘记
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *CustomHTTPProvider) GetDomains() (domains []string, err error) {
|
||||
resp, err := this.post(maps.Map{
|
||||
|
||||
@@ -69,6 +69,19 @@ func (this *DNSPodProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *DNSPodProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if params.GetString("apiType") == "tencentDNS" {
|
||||
params["accessKeySecret"] = MaskString(params.GetString("accessKeySecret"))
|
||||
} else {
|
||||
params["token"] = MaskString(params.GetString("token"))
|
||||
}
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
|
||||
if this.tencentDNSProvider != nil {
|
||||
|
||||
@@ -71,6 +71,14 @@ func (this *EdgeDNSAPIProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *EdgeDNSAPIProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
params["accessKeySecret"] = MaskString(params.GetString("accessKeySecret"))
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *EdgeDNSAPIProvider) GetDomains() (domains []string, err error) {
|
||||
var offset = 0
|
||||
|
||||
@@ -71,6 +71,14 @@ func (this *HuaweiDNSProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *HuaweiDNSProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
params["accessKeySecret"] = MaskString(params.GetString("accessKeySecret"))
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *HuaweiDNSProvider) GetDomains() (domains []string, err error) {
|
||||
var resp = new(huaweidns.ZonesResponse)
|
||||
|
||||
@@ -10,6 +10,9 @@ type ProviderInterface interface {
|
||||
// Auth 认证
|
||||
Auth(params maps.Map) error
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
MaskParams(params maps.Map)
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
GetDomains() (domains []string, err error)
|
||||
|
||||
|
||||
@@ -47,6 +47,14 @@ func (this *TencentDNSProvider) Auth(params maps.Map) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaskParams 对参数进行掩码
|
||||
func (this *TencentDNSProvider) MaskParams(params maps.Map) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
params["accessKeySecret"] = MaskString(params.GetString("accessKeySecret"))
|
||||
}
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *TencentDNSProvider) GetDomains() (domains []string, err error) {
|
||||
var offset int64 = 0
|
||||
|
||||
67
internal/dnsclients/utils.go
Normal file
67
internal/dnsclients/utils.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package dnsclients
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MaskString 对字符串进行掩码
|
||||
func MaskString(s string) string {
|
||||
var l = len(s)
|
||||
if l == 0 {
|
||||
return ""
|
||||
}
|
||||
if l < 8 {
|
||||
return strings.Repeat("*", l)
|
||||
}
|
||||
return s[:4] + strings.Repeat("*", l-4)
|
||||
}
|
||||
|
||||
// IsMasked 判断字符串是否被掩码
|
||||
func IsMasked(s string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
return s == strings.Repeat("*", len(s)) || strings.HasSuffix(s, "**")
|
||||
}
|
||||
|
||||
// UnmaskAPIParams 恢复API参数
|
||||
func UnmaskAPIParams(oldParamsJSON []byte, newParamsJSON []byte) (resultJSON []byte, err error) {
|
||||
var oldParams maps.Map
|
||||
var newParams maps.Map
|
||||
|
||||
if len(oldParamsJSON) == 0 || len(newParamsJSON) == 0 {
|
||||
return newParamsJSON, nil
|
||||
}
|
||||
err = json.Unmarshal(oldParamsJSON, &oldParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(newParamsJSON, &newParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if oldParams == nil || newParams == nil {
|
||||
return newParamsJSON, nil
|
||||
}
|
||||
|
||||
for k, v := range newParams {
|
||||
if v != nil {
|
||||
s, ok := v.(string)
|
||||
if ok && IsMasked(s) {
|
||||
var oldV = oldParams.GetString(k)
|
||||
if len(oldV) > 0 {
|
||||
newParams[k] = oldV
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultJSON, err = json.Marshal(newParams)
|
||||
return
|
||||
}
|
||||
35
internal/dnsclients/utils_test.go
Normal file
35
internal/dnsclients/utils_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package dnsclients_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsMasked(t *testing.T) {
|
||||
var a = assert.NewAssertion(t)
|
||||
a.IsFalse(dnsclients.IsMasked(""))
|
||||
a.IsFalse(dnsclients.IsMasked("abc"))
|
||||
a.IsFalse(dnsclients.IsMasked("abc*"))
|
||||
a.IsTrue(dnsclients.IsMasked("*"))
|
||||
a.IsTrue(dnsclients.IsMasked("**"))
|
||||
a.IsTrue(dnsclients.IsMasked("***"))
|
||||
a.IsTrue(dnsclients.IsMasked("*******"))
|
||||
a.IsTrue(dnsclients.IsMasked("abc**"))
|
||||
a.IsTrue(dnsclients.IsMasked("abcd*********"))
|
||||
}
|
||||
|
||||
func TestUnmaskAPIParams(t *testing.T) {
|
||||
data, err := dnsclients.UnmaskAPIParams([]byte(`{
|
||||
"key": "a",
|
||||
"secret": "abc12"
|
||||
}`), []byte(`{
|
||||
"secret": "abc**"
|
||||
}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(string(data))
|
||||
}
|
||||
39
internal/instances/README.md
Normal file
39
internal/instances/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 实例
|
||||
|
||||
## 目录结构:
|
||||
~~~
|
||||
/opt/cache
|
||||
/usr/local/goedge/
|
||||
edge-admin/
|
||||
configs/
|
||||
api_admin.yaml
|
||||
api_db.yaml
|
||||
server.yaml
|
||||
edge-api/
|
||||
configs/api.yaml
|
||||
configs/db.yaml
|
||||
api-node/
|
||||
configs/api_node.yaml
|
||||
api-user/
|
||||
configs/api_user.yaml
|
||||
src/
|
||||
/usr/bin/
|
||||
edge-admin -> ...
|
||||
edge-api -> ...
|
||||
edge-node -> ...
|
||||
edge-user -> ...
|
||||
/usr/local/mysql
|
||||
~~~
|
||||
|
||||
* 其中 `->` 表示软链接。
|
||||
* `src/` 目录下放置zip格式的待安装压缩包
|
||||
|
||||
## 端口
|
||||
* Admin:7788
|
||||
* API:8001
|
||||
* API HTTP:8002
|
||||
* User: 7799
|
||||
* Server: 8080
|
||||
|
||||
## 数据库
|
||||
数据库名称为 `edges`
|
||||
16
internal/instances/api_config.go
Normal file
16
internal/instances/api_config.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package instances
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type APIConfig struct {
|
||||
RPCEndpoints []string `yaml:"rpc.endpoints,flow,omitempty" json:"rpc.endpoints"`
|
||||
RPCDisableUpdate bool `yaml:"rpc.disableUpdate,omitempty" json:"rpc.disableUpdate"`
|
||||
NodeId string `yaml:"nodeId" json:"nodeId"`
|
||||
Secret string `yaml:"secret" json:"secret"`
|
||||
}
|
||||
|
||||
func (this *APIConfig) AsYAML() ([]byte, error) {
|
||||
return yaml.Marshal(this)
|
||||
}
|
||||
1047
internal/instances/instance.go
Normal file
1047
internal/instances/instance.go
Normal file
File diff suppressed because it is too large
Load Diff
98
internal/instances/instance_test.go
Normal file
98
internal/instances/instance_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package instances_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/instances"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var instance = instances.NewInstance(instances.Options{
|
||||
Cacheable: true,
|
||||
WorkDir: Tea.Root + "/standalone-instance",
|
||||
SrcDir: Tea.Root + "/standalone-instance/src",
|
||||
DB: struct {
|
||||
Host string
|
||||
Port int
|
||||
Username string
|
||||
Password string
|
||||
Name string
|
||||
}{
|
||||
Host: "127.0.0.1",
|
||||
Port: 3306,
|
||||
Username: "root",
|
||||
Password: "123456",
|
||||
Name: "edges2",
|
||||
},
|
||||
AdminNode: struct {
|
||||
Port int
|
||||
}{
|
||||
Port: 7788,
|
||||
},
|
||||
APINode: struct {
|
||||
HTTPPort int
|
||||
RestHTTPPort int
|
||||
}{
|
||||
HTTPPort: 8001,
|
||||
RestHTTPPort: 8002,
|
||||
},
|
||||
Node: struct{ HTTPPort int }{
|
||||
HTTPPort: 8080,
|
||||
},
|
||||
UserNode: struct {
|
||||
HTTPPort int
|
||||
}{
|
||||
HTTPPort: 7799,
|
||||
},
|
||||
})
|
||||
|
||||
func TestInstanceSetupAll(t *testing.T) {
|
||||
err := instance.SetupAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_SetupDB(t *testing.T) {
|
||||
err := instance.SetupDB()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_SetupAdminNode(t *testing.T) {
|
||||
err := instance.SetupAdminNode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_SetupAPINode(t *testing.T) {
|
||||
err := instance.SetupAPINode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_SetupUserNode(t *testing.T) {
|
||||
err := instance.SetupUserNode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_SetupNode(t *testing.T) {
|
||||
err := instance.SetupNode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstance_Clean(t *testing.T) {
|
||||
err := instance.Clean()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
32
internal/instances/options.go
Normal file
32
internal/instances/options.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package instances
|
||||
|
||||
type Options struct {
|
||||
IsTesting bool
|
||||
Verbose bool
|
||||
Cacheable bool
|
||||
|
||||
WorkDir string
|
||||
SrcDir string
|
||||
DB struct {
|
||||
Host string
|
||||
Port int
|
||||
Username string
|
||||
Password string
|
||||
Name string
|
||||
}
|
||||
AdminNode struct {
|
||||
Port int
|
||||
}
|
||||
APINode struct {
|
||||
HTTPPort int
|
||||
RestHTTPPort int
|
||||
}
|
||||
Node struct {
|
||||
HTTPPort int
|
||||
}
|
||||
UserNode struct {
|
||||
HTTPPort int
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,39 @@ func (this *AdminService) CheckAdminUsername(ctx context.Context, req *pb.CheckA
|
||||
return &pb.CheckAdminUsernameResponse{Exists: exists}, nil
|
||||
}
|
||||
|
||||
// FindAdminWithUsername 使用用管理员户名查找管理员信息
|
||||
func (this *AdminService) FindAdminWithUsername(ctx context.Context, req *pb.FindAdminWithUsernameRequest) (*pb.FindAdminWithUsernameResponse, error) {
|
||||
// 校验请求
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
if len(req.Username) == 0 {
|
||||
return nil, errors.New("require 'username'")
|
||||
}
|
||||
admin, err := models.SharedAdminDAO.FindAdminWithUsername(tx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if admin == nil {
|
||||
return &pb.FindAdminWithUsernameResponse{Admin: nil}, nil
|
||||
}
|
||||
|
||||
return &pb.FindAdminWithUsernameResponse{
|
||||
Admin: &pb.Admin{
|
||||
Id: int64(admin.Id),
|
||||
Fullname: admin.Fullname,
|
||||
Username: admin.Username,
|
||||
IsOn: admin.IsOn,
|
||||
IsSuper: admin.IsSuper,
|
||||
CanLogin: admin.CanLogin,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindAdminFullname 获取管理员名称
|
||||
func (this *AdminService) FindAdminFullname(ctx context.Context, req *pb.FindAdminFullnameRequest) (*pb.FindAdminFullnameResponse, error) {
|
||||
// 校验请求
|
||||
|
||||
@@ -2,9 +2,11 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// DNSProviderService DNS服务商相关服务
|
||||
@@ -42,6 +44,21 @@ func (this *DNSProviderService) UpdateDNSProvider(ctx context.Context, req *pb.U
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, req.DnsProviderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if provider == nil {
|
||||
// do nothing here
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// 恢复被掩码的数据
|
||||
req.ApiParamsJSON, err = dnsclients.UnmaskAPIParams(provider.ApiParams, req.ApiParamsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dns.SharedDNSProviderDAO.UpdateDNSProvider(tx, req.DnsProviderId, req.Name, req.ApiParamsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -175,14 +192,34 @@ func (this *DNSProviderService) FindEnabledDNSProvider(ctx context.Context, req
|
||||
return &pb.FindEnabledDNSProviderResponse{DnsProvider: nil}, nil
|
||||
}
|
||||
|
||||
return &pb.FindEnabledDNSProviderResponse{DnsProvider: &pb.DNSProvider{
|
||||
Id: int64(provider.Id),
|
||||
Name: provider.Name,
|
||||
Type: provider.Type,
|
||||
TypeName: dnsclients.FindProviderTypeName(provider.Type),
|
||||
ApiParamsJSON: provider.ApiParams,
|
||||
DataUpdatedAt: int64(provider.DataUpdatedAt),
|
||||
}}, nil
|
||||
if req.MaskParams {
|
||||
var providerObj = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||
if providerObj != nil {
|
||||
var paramsMap = maps.Map{}
|
||||
if len(provider.ApiParams) > 0 {
|
||||
err = json.Unmarshal(provider.ApiParams, ¶msMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providerObj.MaskParams(paramsMap)
|
||||
provider.ApiParams, err = json.Marshal(paramsMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.FindEnabledDNSProviderResponse{
|
||||
DnsProvider: &pb.DNSProvider{
|
||||
Id: int64(provider.Id),
|
||||
Name: provider.Name,
|
||||
Type: provider.Type,
|
||||
TypeName: dnsclients.FindProviderTypeName(provider.Type),
|
||||
ApiParamsJSON: provider.ApiParams,
|
||||
DataUpdatedAt: int64(provider.DataUpdatedAt),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindAllDNSProviderTypes 取得所有服务商类型
|
||||
|
||||
@@ -353,14 +353,28 @@ func (this *HTTPCacheTaskService) FindEnabledHTTPCacheTask(ctx context.Context,
|
||||
key.Errors = nil
|
||||
}
|
||||
|
||||
// 集群信息
|
||||
var pbNodeCluster *pb.NodeCluster
|
||||
if !isFromUser && key.ClusterId > 0 {
|
||||
clusterName, findClusterErr := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(key.ClusterId))
|
||||
if findClusterErr != nil {
|
||||
return nil, findClusterErr
|
||||
}
|
||||
pbNodeCluster = &pb.NodeCluster{
|
||||
Id: int64(key.ClusterId),
|
||||
Name: clusterName,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
NodeCluster: pbNodeCluster,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -972,18 +972,13 @@ func (this *HTTPWebService) FindHTTPWebReferers(ctx context.Context, req *pb.Fin
|
||||
}
|
||||
}
|
||||
|
||||
config, err := models.SharedHTTPWebDAO.FindWebReferers(tx, req.HttpWebId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
referersJSON, err := models.SharedHTTPWebDAO.FindWebReferers(tx, req.HttpWebId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.FindHTTPWebReferersResponse{
|
||||
ReferersJSON: configJSON,
|
||||
ReferersJSON: referersJSON,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1040,18 +1035,13 @@ func (this *HTTPWebService) FindHTTPWebUserAgent(ctx context.Context, req *pb.Fi
|
||||
}
|
||||
}
|
||||
|
||||
config, err := models.SharedHTTPWebDAO.FindWebUserAgent(tx, req.HttpWebId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
userAgentJSON, err := models.SharedHTTPWebDAO.FindWebUserAgent(tx, req.HttpWebId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.FindHTTPWebUserAgentResponse{
|
||||
UserAgentJSON: configJSON,
|
||||
UserAgentJSON: userAgentJSON,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -48,6 +50,25 @@ func (this *NodeGrantService) UpdateNodeGrant(ctx context.Context, req *pb.Updat
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 从掩码中恢复密码和私钥
|
||||
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(tx, req.NodeGrantId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if grant == nil {
|
||||
// do nothing here
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
var maskReg = regexp.MustCompile(`^\*+$`)
|
||||
if len(req.Password) > 0 && maskReg.MatchString(req.Password) {
|
||||
req.Password = grant.Password
|
||||
}
|
||||
|
||||
if len(req.PrivateKey) > 0 && strings.HasSuffix(req.PrivateKey, "********") {
|
||||
req.PrivateKey = grant.PrivateKey
|
||||
}
|
||||
|
||||
err = models.SharedNodeGrantDAO.UpdateGrant(tx, req.NodeGrantId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId, req.Su)
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
@@ -88,9 +88,9 @@ func (this *RegionProvinceService) FindAllRegionProvincesWithRegionCountryId(ctx
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []*pb.RegionProvince{}
|
||||
var pbProvinces = []*pb.RegionProvince{}
|
||||
for _, province := range provinces {
|
||||
result = append(result, &pb.RegionProvince{
|
||||
pbProvinces = append(pbProvinces, &pb.RegionProvince{
|
||||
Id: int64(province.ValueId),
|
||||
Name: province.Name,
|
||||
Codes: province.DecodeCodes(),
|
||||
@@ -101,7 +101,61 @@ func (this *RegionProvinceService) FindAllRegionProvincesWithRegionCountryId(ctx
|
||||
}
|
||||
|
||||
return &pb.FindAllRegionProvincesWithRegionCountryIdResponse{
|
||||
RegionProvinces: result,
|
||||
RegionProvinces: pbProvinces,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindAllRegionProvinces 查找所有国家|地区的所有省份
|
||||
func (this *RegionProvinceService) FindAllRegionProvinces(ctx context.Context, req *pb.FindAllRegionProvincesRequest) (*pb.FindAllRegionProvincesResponse, error) {
|
||||
_, _, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
provinces, err := regions.SharedRegionProvinceDAO.FindAllEnabledProvinces(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbProvinces = []*pb.RegionProvince{}
|
||||
var countryRouteCodeCache = map[int64]string{} // countryId => routeCode
|
||||
for _, province := range provinces {
|
||||
// 国家|地区ID
|
||||
var countryId = int64(province.CountryId)
|
||||
if countryId <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 国家|地区线路
|
||||
countryRouteCode, ok := countryRouteCodeCache[countryId]
|
||||
if !ok {
|
||||
countryRouteCode, err = regions.SharedRegionCountryDAO.FindRegionCountryRouteCode(tx, countryId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
countryRouteCodeCache[countryId] = countryRouteCode
|
||||
}
|
||||
if len(countryRouteCode) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
pbProvinces = append(pbProvinces, &pb.RegionProvince{
|
||||
Id: int64(province.ValueId),
|
||||
Name: province.Name,
|
||||
Codes: province.DecodeCodes(),
|
||||
CustomName: province.CustomName,
|
||||
CustomCodes: province.DecodeCustomCodes(),
|
||||
DisplayName: province.DisplayName(),
|
||||
RegionCountryId: countryId,
|
||||
RegionCountry: &pb.RegionCountry{
|
||||
Id: countryId,
|
||||
RouteCode: countryRouteCode,
|
||||
},
|
||||
})
|
||||
}
|
||||
return &pb.FindAllRegionProvincesResponse{
|
||||
RegionProvinces: pbProvinces,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,12 @@ func (this *SQLExecutor) Run(showLog bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// prevent default configure loading
|
||||
var globalConfig = dbs.GlobalConfig()
|
||||
if globalConfig != nil && len(globalConfig.DBs) == 0 {
|
||||
globalConfig.DBs = map[string]*dbs.DBConfig{"prod": this.dbConfig}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
@@ -91,56 +97,56 @@ func (this *SQLExecutor) checkData(db *dbs.DB) error {
|
||||
// 检查管理员平台节点
|
||||
err := this.checkAdminNode(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check admin node failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查用户平台节点
|
||||
err = this.checkUserNode(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check user node failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查集群配置
|
||||
err = this.checkCluster(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check cluster failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查初始化用户
|
||||
// 需要放在检查集群后面
|
||||
err = this.checkUser(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check user failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查IP名单
|
||||
err = this.checkIPList(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check ip list failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查指标设置
|
||||
err = this.checkMetricItems(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check metric items failed: %w", err)
|
||||
}
|
||||
|
||||
// 检查自建DNS全局设置
|
||||
err = this.checkNS(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check ns failed: %w", err)
|
||||
}
|
||||
|
||||
// 更新Agents
|
||||
err = this.checkClientAgents(db)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("check client agents failed: %w", err)
|
||||
}
|
||||
|
||||
// 更新版本号
|
||||
err = this.updateVersion(db, ComposeSQLVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("update version failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -180,13 +186,13 @@ func (this *SQLExecutor) checkAdminNode(db *dbs.DB) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
count := types.Int(col)
|
||||
var count = types.Int(col)
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeId := rands.HexString(32)
|
||||
secret := rands.String(32)
|
||||
var nodeId = rands.HexString(32)
|
||||
var secret = rands.String(32)
|
||||
_, err = db.Exec("INSERT INTO edgeAPITokens (nodeId, secret, role) VALUES (?, ?, ?)", nodeId, secret, "admin")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -208,13 +214,13 @@ func (this *SQLExecutor) checkUserNode(db *dbs.DB) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
count := types.Int(col)
|
||||
var count = types.Int(col)
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeId := rands.HexString(32)
|
||||
secret := rands.String(32)
|
||||
var nodeId = rands.HexString(32)
|
||||
var secret = rands.String(32)
|
||||
_, err = db.Exec("INSERT INTO edgeAPITokens (nodeId, secret, role) VALUES (?, ?, ?)", nodeId, secret, "user")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -225,7 +231,7 @@ func (this *SQLExecutor) checkUserNode(db *dbs.DB) error {
|
||||
|
||||
// 检查集群配置
|
||||
func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
||||
/// 检查是否有集群数字
|
||||
/// 检查是否有集群数据
|
||||
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeNodeClusters")
|
||||
if err != nil {
|
||||
return fmt.Errorf("query clusters failed: %w", err)
|
||||
@@ -238,7 +244,7 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("query clusters failed: %w", err)
|
||||
}
|
||||
count := types.Int(col)
|
||||
var count = types.Int(col)
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -281,6 +287,7 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
||||
}
|
||||
|
||||
// 默认缓存策略
|
||||
|
||||
models.SharedHTTPCachePolicyDAO = models.NewHTTPCachePolicyDAO()
|
||||
models.SharedHTTPCachePolicyDAO.Instance = db
|
||||
policyId, err := models.SharedHTTPCachePolicyDAO.CreateDefaultCachePolicy(nil, "默认集群")
|
||||
@@ -305,6 +312,15 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
||||
models.SharedHTTPFirewallRuleDAO = models.NewHTTPFirewallRuleDAO()
|
||||
models.SharedHTTPFirewallRuleDAO.Instance = db
|
||||
|
||||
models.SharedHTTPWebDAO = models.NewHTTPWebDAO()
|
||||
models.SharedHTTPWebDAO.Instance = db
|
||||
|
||||
models.SharedServerDAO = models.NewServerDAO()
|
||||
models.SharedServerDAO.Instance = db
|
||||
|
||||
models.SharedNodeClusterDAO = models.NewNodeClusterDAO()
|
||||
models.SharedNodeClusterDAO.Instance = db
|
||||
|
||||
policyId, err = models.SharedHTTPFirewallPolicyDAO.CreateDefaultFirewallPolicy(nil, "默认集群")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -331,7 +347,7 @@ func (this *SQLExecutor) checkIPList(db *dbs.DB) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("query ip lists failed: %w", err)
|
||||
}
|
||||
count := types.Int(col)
|
||||
var count = types.Int(col)
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -388,7 +404,7 @@ func (this *SQLExecutor) checkMetricItems(db *dbs.DB) error {
|
||||
|
||||
// chart
|
||||
for _, chartMap := range chartMaps {
|
||||
chartCode := chartMap.GetString("code")
|
||||
var chartCode = chartMap.GetString("code")
|
||||
one, err := db.FindOne("SELECT id FROM edgeMetricCharts WHERE itemId=? AND code=? LIMIT 1", itemId, chartCode)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -528,7 +544,7 @@ func (this *SQLExecutor) updateVersion(db *dbs.DB, version string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("query version failed: %w", err)
|
||||
}
|
||||
count := types.Int(col)
|
||||
var count = types.Int(col)
|
||||
if count > 0 {
|
||||
_, err = db.Exec("UPDATE edgeVersions SET version=?", version)
|
||||
if err != nil {
|
||||
|
||||
@@ -106,6 +106,9 @@ var upgradeFuncs = []*upgradeVersion{
|
||||
{
|
||||
"1.3.2", upgradeV1_3_2,
|
||||
},
|
||||
{
|
||||
"1.3.4", upgradeV1_3_4,
|
||||
},
|
||||
}
|
||||
|
||||
// UpgradeSQLData 升级SQL数据
|
||||
@@ -1230,3 +1233,13 @@ func upgradeV1_3_2(db *dbs.DB) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 1.3.4
|
||||
func upgradeV1_3_4(db *dbs.DB) error {
|
||||
_, err := db.Exec("DELETE FROM edgeLoginSessions WHERE adminId>0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,3 +27,26 @@ func TestUpgradeSQLData_v0_5_6(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
|
||||
func TestUpgradeSQLData_v1_3_4(t *testing.T) {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
|
||||
err = upgradeV1_3_4(db)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -113,6 +113,12 @@ func (this *ServiceManager) installSystemdService(systemd, exePath string, args
|
||||
shortName := teaconst.SystemdServiceName
|
||||
longName := "GoEdge API" // TODO 将来可以修改
|
||||
|
||||
var startCmd = exePath + " daemon"
|
||||
bashPath, _ := executils.LookPath("bash")
|
||||
if len(bashPath) > 0 {
|
||||
startCmd = bashPath + " -c \"" + startCmd + "\""
|
||||
}
|
||||
|
||||
desc := `### BEGIN INIT INFO
|
||||
# Provides: ` + shortName + `
|
||||
# Required-Start: $all
|
||||
@@ -131,7 +137,7 @@ After=network-online.target
|
||||
Type=simple
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
ExecStart=` + exePath + ` daemon
|
||||
ExecStart=` + startCmd + `
|
||||
ExecStop=` + exePath + ` stop
|
||||
ExecReload=` + exePath + ` reload
|
||||
|
||||
|
||||
Reference in New Issue
Block a user