Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
476ff91bf8 | ||
|
|
ac6b10489e | ||
|
|
9352e1837f | ||
|
|
ddec102d18 | ||
|
|
0d50b9b0cc | ||
|
|
20b4b47eea | ||
|
|
ee8396c760 | ||
|
|
c3fa6a753a | ||
|
|
fbe4de2e94 | ||
|
|
f5c7108799 | ||
|
|
5825a7e654 | ||
|
|
a6911117af | ||
|
|
b428db4f5e | ||
|
|
e4145a2059 | ||
|
|
af13357985 |
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "1.0.1"
|
||||
Version = "1.0.4"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "1.0.1"
|
||||
NodeVersion = "1.0.4"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
SQLVersion = "11"
|
||||
|
||||
@@ -131,6 +131,8 @@ func (this *ACMEUserDAO) CountACMEUsersWithAdminId(tx *dbs.Tx, adminId int64, us
|
||||
}
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
} else {
|
||||
query.Attr("userId", 0)
|
||||
}
|
||||
if accountId > 0 {
|
||||
query.Attr("accountId", accountId)
|
||||
@@ -149,6 +151,8 @@ func (this *ACMEUserDAO) ListACMEUsers(tx *dbs.Tx, adminId int64, userId int64,
|
||||
}
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
} else {
|
||||
query.Attr("userId", 0)
|
||||
}
|
||||
|
||||
_, err = query.
|
||||
|
||||
@@ -237,7 +237,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
|
||||
if len(accessLog.TimeISO8601) > 10 {
|
||||
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
|
||||
} else {
|
||||
timeutil.FormatTime("Ymd", accessLog.Timestamp)
|
||||
day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
|
||||
}
|
||||
|
||||
tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true)
|
||||
|
||||
@@ -416,10 +416,10 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUse
|
||||
// ListIPItemsAfterVersion 根据版本号查找IP列表
|
||||
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
|
||||
_, err = this.Query(tx).
|
||||
UseIndex("version").
|
||||
// 这里不要设置状态参数,因为我们要知道哪些是删除的
|
||||
Gt("version", version).
|
||||
Asc("version").
|
||||
Asc("id").
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
|
||||
@@ -356,7 +356,7 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
|
||||
|
||||
// 关键词
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))").
|
||||
query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR "+this.Table+".id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))").
|
||||
Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
|
||||
|
||||
@@ -684,7 +684,7 @@ func (this *SSLCertDAO) buildDomainSearchingQuery(query *dbs.Query, domains []st
|
||||
for _, domain := range domains {
|
||||
domainMap[domain] = true
|
||||
}
|
||||
var reg = regexp.MustCompile(`^[\w.-]+$`) // 为了下面的SQL语句安全先不支持其他字符
|
||||
var reg = regexp.MustCompile(`^[\w*.-]+$`) // 为了下面的SQL语句安全先不支持其他字符
|
||||
for domain := range domainMap {
|
||||
if !reg.MatchString(domain) {
|
||||
continue
|
||||
@@ -729,7 +729,9 @@ func (this *SSLCertDAO) buildDomainSearchingQuery(query *dbs.Query, domains []st
|
||||
|
||||
sqlPieces = append(sqlPieces, "JSON_CONTAINS(dnsNames, '"+string(domainJSON)+"')")
|
||||
}
|
||||
query.Where("(" + strings.Join(sqlPieces, " OR ") + ")")
|
||||
if len(sqlPieces) > 0 {
|
||||
query.Where("(" + strings.Join(sqlPieces, " OR ") + ")")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package dnspod
|
||||
|
||||
type CustomLineGroupListResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
LineGroups []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"line_groups"`
|
||||
Info struct {
|
||||
NowTotal int `json:"now_total"`
|
||||
Total int `json:"total"`
|
||||
} `json:"info"`
|
||||
} `json:"data"`
|
||||
}
|
||||
@@ -164,6 +164,53 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
|
||||
})
|
||||
}
|
||||
|
||||
// 自定义线路分组
|
||||
var groupsPerPage = 100
|
||||
var customLineGroupListResponse = new(dnspod.CustomLineGroupListResponse)
|
||||
err = this.doAPI("/Custom.Line.Group.List", map[string]string{
|
||||
"domain": domain,
|
||||
"offset": "0",
|
||||
"length": types.String(groupsPerPage),
|
||||
}, customLineGroupListResponse)
|
||||
if err != nil {
|
||||
// 忽略自定义分组错误
|
||||
err = nil
|
||||
} else {
|
||||
if len(customLineGroupListResponse.Data.LineGroups) > 0 {
|
||||
for _, lineGroup := range customLineGroupListResponse.Data.LineGroups {
|
||||
routes = append(routes, &dnstypes.Route{
|
||||
Name: "分组:" + lineGroup.Name,
|
||||
Code: lineGroup.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if customLineGroupListResponse.Data.Info.Total > customLineGroupListResponse.Data.Info.NowTotal {
|
||||
for page := 1; page <= 100; /** 最多100页 **/ page++ {
|
||||
err = this.doAPI("/Custom.Line.Group.List", map[string]string{
|
||||
"domain": domain,
|
||||
"offset": types.String(page * groupsPerPage),
|
||||
"length": types.String(groupsPerPage),
|
||||
}, customLineGroupListResponse)
|
||||
if err != nil {
|
||||
// 忽略错误
|
||||
err = nil
|
||||
} else {
|
||||
if len(customLineGroupListResponse.Data.LineGroups) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for _, lineGroup := range customLineGroupListResponse.Data.LineGroups {
|
||||
routes = append(routes, &dnstypes.Route{
|
||||
Name: "分组:" + lineGroup.Name,
|
||||
Code: lineGroup.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/iwind/TeaGo/files"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var SharedDeployManager = NewDeployManager()
|
||||
@@ -12,9 +13,12 @@ var SharedDeployManager = NewDeployManager()
|
||||
// DeployManager 节点部署文件管理器
|
||||
// 如果节点部署文件有变化,需要重启API节点以便于生效
|
||||
type DeployManager struct {
|
||||
dir string
|
||||
dir string
|
||||
|
||||
nodeFiles []*DeployFile
|
||||
nsNodeFiles []*DeployFile
|
||||
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
// NewDeployManager 获取新节点部署文件管理器
|
||||
@@ -29,24 +33,27 @@ func NewDeployManager() *DeployManager {
|
||||
|
||||
// LoadNodeFiles 加载所有边缘节点文件
|
||||
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
if len(this.nodeFiles) > 0 {
|
||||
return this.nodeFiles
|
||||
}
|
||||
|
||||
keyMap := map[string]*DeployFile{} // key => File
|
||||
var keyMap = map[string]*DeployFile{} // key => File
|
||||
|
||||
reg := regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
var reg = regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
for _, file := range files.NewFile(this.dir).List() {
|
||||
name := file.Name()
|
||||
var name = file.Name()
|
||||
if !reg.MatchString(name) {
|
||||
continue
|
||||
}
|
||||
matches := reg.FindStringSubmatch(name)
|
||||
osName := matches[1]
|
||||
arch := matches[2]
|
||||
version := matches[3]
|
||||
var matches = reg.FindStringSubmatch(name)
|
||||
var osName = matches[1]
|
||||
var arch = matches[2]
|
||||
var version = matches[3]
|
||||
|
||||
key := osName + "_" + arch
|
||||
var key = osName + "_" + arch
|
||||
oldFile, ok := keyMap[key]
|
||||
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
||||
continue
|
||||
@@ -59,7 +66,7 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
||||
}
|
||||
}
|
||||
|
||||
result := []*DeployFile{}
|
||||
var result = []*DeployFile{}
|
||||
for _, v := range keyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
@@ -81,24 +88,27 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
|
||||
|
||||
// LoadNSNodeFiles 加载所有NS节点安装文件
|
||||
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
if len(this.nsNodeFiles) > 0 {
|
||||
return this.nsNodeFiles
|
||||
}
|
||||
|
||||
keyMap := map[string]*DeployFile{} // key => File
|
||||
var keyMap = map[string]*DeployFile{} // key => File
|
||||
|
||||
reg := regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
var reg = regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
for _, file := range files.NewFile(this.dir).List() {
|
||||
name := file.Name()
|
||||
var name = file.Name()
|
||||
if !reg.MatchString(name) {
|
||||
continue
|
||||
}
|
||||
matches := reg.FindStringSubmatch(name)
|
||||
osName := matches[1]
|
||||
arch := matches[2]
|
||||
version := matches[3]
|
||||
var matches = reg.FindStringSubmatch(name)
|
||||
var osName = matches[1]
|
||||
var arch = matches[2]
|
||||
var version = matches[3]
|
||||
|
||||
key := osName + "_" + arch
|
||||
var key = osName + "_" + arch
|
||||
oldFile, ok := keyMap[key]
|
||||
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
||||
continue
|
||||
@@ -111,7 +121,7 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
||||
}
|
||||
}
|
||||
|
||||
result := []*DeployFile{}
|
||||
var result = []*DeployFile{}
|
||||
for _, v := range keyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
@@ -130,3 +140,12 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reload 重置缓存
|
||||
func (this *DeployManager) Reload() {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
this.nodeFiles = nil
|
||||
this.nsNodeFiles = nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package nodes
|
||||
@@ -31,7 +32,7 @@ func (this *NodeStatusExecutor) updateMem(status *nodeconfigs.NodeStatus) {
|
||||
if minFreeMemory > 1<<30 {
|
||||
minFreeMemory = 1 << 30
|
||||
}
|
||||
if stat.Free < minFreeMemory {
|
||||
if stat.Available > 0 && stat.Available < minFreeMemory {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
|
||||
@@ -232,6 +232,12 @@ func (this *ACMETaskService) CreateACMETask(ctx context.Context, req *pb.CreateA
|
||||
req.AuthType = acme.AuthTypeDNS
|
||||
}
|
||||
|
||||
if adminId > 0 {
|
||||
if req.UserId > 0 {
|
||||
userId = req.UserId
|
||||
}
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
taskId, err := acmemodels.SharedACMETaskDAO.CreateACMETask(tx, adminId, userId, req.AuthType, req.AcmeUserId, req.DnsProviderId, req.DnsDomain, req.Domains, req.AutoRenew, req.AuthURL)
|
||||
if err != nil {
|
||||
|
||||
@@ -22,6 +22,12 @@ func (this *ACMEUserService) CreateACMEUser(ctx context.Context, req *pb.CreateA
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
if adminId > 0 {
|
||||
if req.UserId > 0 {
|
||||
userId = req.UserId
|
||||
}
|
||||
}
|
||||
|
||||
acmeUserId, err := acmemodels.SharedACMEUserDAO.CreateACMEUser(tx, adminId, userId, req.AcmeProviderCode, req.AcmeProviderAccountId, req.Email, req.Description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
@@ -481,3 +482,106 @@ func (this *APINodeService) UploadAPINodeFile(ctx context.Context, req *pb.Uploa
|
||||
|
||||
return &pb.UploadAPINodeFileResponse{}, nil
|
||||
}
|
||||
|
||||
// UploadDeployFileToAPINode 上传节点安装文件
|
||||
func (this *APINodeService) UploadDeployFileToAPINode(ctx context.Context, req *pb.UploadDeployFileToAPINodeRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var targetDir = Tea.Root + "/deploy/"
|
||||
var targetTmpFile = targetDir + "/" + req.Filename + ".tmp"
|
||||
var targetFile = targetDir + "/" + req.Filename
|
||||
|
||||
if req.IsFirstChunk {
|
||||
_ = os.Remove(targetTmpFile)
|
||||
}
|
||||
|
||||
if len(req.ChunkData) > 0 {
|
||||
err = func() error {
|
||||
var flags = os.O_CREATE | os.O_WRONLY
|
||||
if req.IsFirstChunk {
|
||||
flags |= os.O_TRUNC
|
||||
} else {
|
||||
flags |= os.O_APPEND
|
||||
}
|
||||
fp, err := os.OpenFile(targetTmpFile, flags, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = fp.Close()
|
||||
}()
|
||||
|
||||
_, err = fp.Write(req.ChunkData)
|
||||
return err
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, errors.New("write file failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if req.IsLastChunk {
|
||||
// 检查SUM
|
||||
fp, err := os.Open(targetTmpFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var hash = md5.New()
|
||||
_, err = io.Copy(hash, fp)
|
||||
_ = fp.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tmpSum = fmt.Sprintf("%x", hash.Sum(nil))
|
||||
if tmpSum != req.Sum {
|
||||
_ = os.Remove(targetTmpFile)
|
||||
return nil, errors.New("check sum failed")
|
||||
}
|
||||
|
||||
// 正式改名
|
||||
err = os.Rename(targetTmpFile, targetFile)
|
||||
if err != nil {
|
||||
return nil, errors.New("rename failed: " + err.Error())
|
||||
}
|
||||
|
||||
// 重载数据
|
||||
installers.SharedDeployManager.Reload()
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindLatestDeployFiles 查找已有节点安装文件信息
|
||||
func (this *APINodeService) FindLatestDeployFiles(ctx context.Context, req *pb.FindLatestDeployFilesRequest) (*pb.FindLatestDeployFilesResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbNodeFiles = []*pb.FindLatestDeployFilesResponse_DeployFile{}
|
||||
var nodeFiles = installers.SharedDeployManager.LoadNodeFiles()
|
||||
for _, nodeFile := range nodeFiles {
|
||||
pbNodeFiles = append(pbNodeFiles, &pb.FindLatestDeployFilesResponse_DeployFile{
|
||||
Os: nodeFile.OS,
|
||||
Arch: nodeFile.Arch,
|
||||
Version: nodeFile.Version,
|
||||
})
|
||||
}
|
||||
|
||||
var pbNSNodeFiles = []*pb.FindLatestDeployFilesResponse_DeployFile{}
|
||||
var nsNodeFiles = installers.SharedDeployManager.LoadNSNodeFiles()
|
||||
for _, nodeFile := range nsNodeFiles {
|
||||
pbNSNodeFiles = append(pbNSNodeFiles, &pb.FindLatestDeployFilesResponse_DeployFile{
|
||||
Os: nodeFile.OS,
|
||||
Arch: nodeFile.Arch,
|
||||
Version: nodeFile.Version,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.FindLatestDeployFilesResponse{
|
||||
NodeDeployFiles: pbNodeFiles,
|
||||
NsNodeDeployFiles: pbNSNodeFiles,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -29,8 +29,29 @@ func (this *HTTPCacheTaskService) CreateHTTPCacheTask(ctx context.Context, req *
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查操作类型
|
||||
if len(req.Type) == 0 {
|
||||
return nil, errors.New("require 'type' parameter")
|
||||
}
|
||||
if req.Type != models.HTTPCacheTaskTypePurge && req.Type != models.HTTPCacheTaskTypeFetch {
|
||||
return nil, errors.New("invalid type '" + req.Type + "'")
|
||||
return nil, errors.New("'type' must be 'purge' or 'fetch'")
|
||||
}
|
||||
|
||||
// 检查Key类型
|
||||
if len(req.KeyType) == 0 {
|
||||
return nil, errors.New("require 'keyType' parameter")
|
||||
}
|
||||
if req.KeyType != "key" && req.KeyType != "prefix" {
|
||||
return nil, errors.New("'keyType' must be 'key' or 'prefix'")
|
||||
}
|
||||
|
||||
// 预热只能是Key
|
||||
if req.Type == models.HTTPCacheTaskTypeFetch && req.KeyType != "key" {
|
||||
return nil, errors.New("'keyType' should be 'key' when fetching cache")
|
||||
}
|
||||
|
||||
// 检查key是否为空
|
||||
if len(req.Keys) == 0 {
|
||||
return nil, errors.New("'keys' should not be empty")
|
||||
}
|
||||
|
||||
// 检查Key数量
|
||||
|
||||
@@ -195,6 +195,9 @@ func (this *IPLibraryService) LookupIPRegion(ctx context.Context, req *pb.Lookup
|
||||
Isp: result.ProviderName(),
|
||||
CountryId: result.CountryId(),
|
||||
ProvinceId: result.ProvinceId(),
|
||||
CityId: result.CityId(),
|
||||
TownId: result.TownId(),
|
||||
ProviderId: result.ProviderId(),
|
||||
Summary: result.Summary(),
|
||||
}}, nil
|
||||
}
|
||||
@@ -213,12 +216,17 @@ func (this *IPLibraryService) LookupIPRegions(ctx context.Context, req *pb.Looku
|
||||
var info = iplibrary.LookupIP(ip)
|
||||
if info != nil && info.IsOk() {
|
||||
result[ip] = &pb.IPRegion{
|
||||
Country: info.CountryName(),
|
||||
Region: "",
|
||||
Province: info.ProvinceName(),
|
||||
City: info.CityName(),
|
||||
Isp: info.ProviderName(),
|
||||
Summary: info.Summary(),
|
||||
Country: info.CountryName(),
|
||||
Region: "",
|
||||
Province: info.ProvinceName(),
|
||||
City: info.CityName(),
|
||||
Isp: info.ProviderName(),
|
||||
CountryId: info.CountryId(),
|
||||
ProvinceId: info.ProvinceId(),
|
||||
CityId: info.CityId(),
|
||||
TownId: info.TownId(),
|
||||
ProviderId: info.ProviderId(),
|
||||
Summary: info.Summary(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,7 @@ package setup
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
)
|
||||
|
||||
//go:embed sql.json
|
||||
var sqlData []byte
|
||||
|
||||
func init() {
|
||||
err := json.Unmarshal(sqlData, LatestSQLResult)
|
||||
if err != nil {
|
||||
logs.Println("[ERROR]load sql failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62184,7 +62184,7 @@
|
||||
"name": "edgeIPItems",
|
||||
"engine": "InnoDB",
|
||||
"charset": "utf8mb4_general_ci",
|
||||
"definition": "CREATE TABLE `edgeIPItems` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `listId` int(11) unsigned DEFAULT '0' COMMENT '所属名单ID',\n `type` varchar(64) DEFAULT 'ipv4' COMMENT '类型',\n `ipFrom` varchar(64) DEFAULT NULL COMMENT '开始IP',\n `ipTo` varchar(64) DEFAULT NULL COMMENT '结束IP',\n `ipFromLong` bigint(20) unsigned DEFAULT '0' COMMENT '开始IP整型',\n `ipToLong` bigint(20) unsigned DEFAULT '0' COMMENT '结束IP整型',\n `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `updatedAt` bigint(11) unsigned DEFAULT '0' COMMENT '修改时间',\n `reason` varchar(255) DEFAULT NULL COMMENT '加入说明',\n `eventLevel` varchar(64) DEFAULT NULL COMMENT '事件级别',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n `expiredAt` bigint(11) unsigned DEFAULT '0' COMMENT '过期时间',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '有效范围服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '有效范围节点ID',\n `sourceNodeId` int(11) unsigned DEFAULT '0' COMMENT '来源节点ID',\n `sourceServerId` int(11) unsigned DEFAULT '0' COMMENT '来源服务ID',\n `sourceHTTPFirewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT '来源策略ID',\n `sourceHTTPFirewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT '来源规则集分组ID',\n `sourceHTTPFirewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT '来源规则集ID',\n `sourceUserId` bigint(11) unsigned DEFAULT '0' COMMENT '用户ID',\n `isRead` tinyint(1) unsigned DEFAULT '1' COMMENT '是否已读',\n PRIMARY KEY (`id`),\n KEY `listId` (`listId`),\n KEY `version_expiredAt` (`version`,`expiredAt`) USING BTREE,\n KEY `ipFrom` (`ipFrom`),\n KEY `serverId` (`serverId`),\n KEY `expiredAt_state` (`expiredAt`,`state`) USING BTREE,\n KEY `isRead` (`expiredAt`,`isRead`) USING BTREE,\n KEY `createdAt` (`createdAt`),\n KEY `sourceUserId` (`sourceUserId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP'",
|
||||
"definition": "CREATE TABLE `edgeIPItems` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `listId` int(11) unsigned DEFAULT '0' COMMENT '所属名单ID',\n `type` varchar(64) DEFAULT 'ipv4' COMMENT '类型',\n `ipFrom` varchar(64) DEFAULT NULL COMMENT '开始IP',\n `ipTo` varchar(64) DEFAULT NULL COMMENT '结束IP',\n `ipFromLong` bigint(20) unsigned DEFAULT '0' COMMENT '开始IP整型',\n `ipToLong` bigint(20) unsigned DEFAULT '0' COMMENT '结束IP整型',\n `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `updatedAt` bigint(11) unsigned DEFAULT '0' COMMENT '修改时间',\n `reason` varchar(255) DEFAULT NULL COMMENT '加入说明',\n `eventLevel` varchar(64) DEFAULT NULL COMMENT '事件级别',\n `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n `expiredAt` bigint(11) unsigned DEFAULT '0' COMMENT '过期时间',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '有效范围服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '有效范围节点ID',\n `sourceNodeId` int(11) unsigned DEFAULT '0' COMMENT '来源节点ID',\n `sourceServerId` int(11) unsigned DEFAULT '0' COMMENT '来源服务ID',\n `sourceHTTPFirewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT '来源策略ID',\n `sourceHTTPFirewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT '来源规则集分组ID',\n `sourceHTTPFirewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT '来源规则集ID',\n `sourceUserId` bigint(11) unsigned DEFAULT '0' COMMENT '用户ID',\n `isRead` tinyint(1) unsigned DEFAULT '1' COMMENT '是否已读',\n PRIMARY KEY (`id`),\n KEY `listId` (`listId`),\n KEY `ipFrom` (`ipFrom`),\n KEY `serverId` (`serverId`),\n KEY `expiredAt_state` (`expiredAt`,`state`) USING BTREE,\n KEY `isRead` (`expiredAt`,`isRead`) USING BTREE,\n KEY `createdAt` (`createdAt`),\n KEY `sourceUserId` (`sourceUserId`),\n KEY `version` (`version`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP'",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
@@ -62288,10 +62288,6 @@
|
||||
"name": "listId",
|
||||
"definition": "KEY `listId` (`listId`) USING BTREE"
|
||||
},
|
||||
{
|
||||
"name": "version_expiredAt",
|
||||
"definition": "KEY `version_expiredAt` (`version`,`expiredAt`) USING BTREE"
|
||||
},
|
||||
{
|
||||
"name": "ipFrom",
|
||||
"definition": "KEY `ipFrom` (`ipFrom`) USING BTREE"
|
||||
@@ -62315,6 +62311,10 @@
|
||||
{
|
||||
"name": "sourceUserId",
|
||||
"definition": "KEY `sourceUserId` (`sourceUserId`) USING BTREE"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"definition": "KEY `version` (`version`) USING BTREE"
|
||||
}
|
||||
],
|
||||
"records": []
|
||||
|
||||
@@ -12,14 +12,13 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var LatestSQLResult = &SQLDumpResult{}
|
||||
|
||||
// SQLExecutor 安装或升级SQL执行器
|
||||
type SQLExecutor struct {
|
||||
dbConfig *dbs.DBConfig
|
||||
@@ -65,7 +64,14 @@ func (this *SQLExecutor) Run(showLog bool) error {
|
||||
if this.logWriter != nil {
|
||||
showLog = true
|
||||
}
|
||||
_, err = sqlDump.Apply(db, LatestSQLResult, showLog)
|
||||
|
||||
var sqlResult = &SQLDumpResult{}
|
||||
err = json.Unmarshal(sqlData, sqlResult)
|
||||
if err != nil {
|
||||
return errors.New("decode sql data failed: " + err.Error())
|
||||
}
|
||||
|
||||
_, err = sqlDump.Apply(db, sqlResult, showLog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,8 +87,14 @@ func (this *SQLExecutor) Run(showLog bool) error {
|
||||
|
||||
// 检查数据
|
||||
func (this *SQLExecutor) checkData(db *dbs.DB) error {
|
||||
// 检查初始化用户
|
||||
err := this.checkUser(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查管理员平台节点
|
||||
err := this.checkAdminNode(db)
|
||||
err = this.checkAdminNode(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -132,6 +144,20 @@ func (this *SQLExecutor) checkData(db *dbs.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建初始用户
|
||||
func (this *SQLExecutor) checkUser(db *dbs.DB) error {
|
||||
one, err := db.FindOne("SELECT id FROM edgeUsers LIMIT 1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(one) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO edgeUsers (`username`, `password`, `fullname`, `isOn`, `state`, `createdAt`) VALUES (?, ?, ?, ?, ?, ?)", "USER-"+rands.HexString(10), stringutil.Md5(rands.HexString(32)), "默认用户", 1, 1, time.Now().Unix())
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查管理员平台节点
|
||||
func (this *SQLExecutor) checkAdminNode(db *dbs.DB) error {
|
||||
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeAPITokens WHERE role='admin'")
|
||||
|
||||
Reference in New Issue
Block a user