Compare commits

..

15 Commits

Author SHA1 Message Date
刘祥超
476ff91bf8 版本号修改为1.0.4 2023-04-24 10:18:26 +08:00
刘祥超
ac6b10489e DNSPod支持自定义线路分组 2023-04-24 09:37:26 +08:00
刘祥超
9352e1837f 创建初始化用户 2023-04-23 20:13:55 +08:00
刘祥超
ddec102d18 远程升级API节点时自动上传边缘节点安装文件 2023-04-23 19:42:51 +08:00
刘祥超
0d50b9b0cc 创建ACME用户、ACME任务时可以指定平台用户 2023-04-23 15:00:13 +08:00
刘祥超
20b4b47eea 优化edgeIPItems索引 2023-04-23 09:44:06 +08:00
刘祥超
ee8396c760 修复在节点列表中不能同时使用关键词和排序的问题 2023-04-21 15:27:24 +08:00
刘祥超
c3fa6a753a 修复只有一个泛域名时无法查询匹配证书的问题 2023-04-21 10:41:20 +08:00
刘祥超
fbe4de2e94 节点版本号修改为1.1.0 2023-04-19 21:02:01 +08:00
刘祥超
f5c7108799 IP库查询提供更多信息 2023-04-19 20:36:48 +08:00
刘祥超
5825a7e654 修复一处访问日志可能无法正确获得对应日期的问题 2023-04-18 17:54:01 +08:00
刘祥超
a6911117af 优化可用内存检查 2023-04-11 18:52:43 +08:00
刘祥超
b428db4f5e 版本号改为1.1.0 2023-04-10 21:03:31 +08:00
刘祥超
e4145a2059 优化启动速度 2023-04-10 20:57:38 +08:00
刘祥超
af13357985 创建缓存任务接口增加参数校验 2023-04-10 17:13:20 +08:00
18 changed files with 304 additions and 52 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(),
}
}
}

View File

@@ -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())
}
}

View File

@@ -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": []

View File

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