Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14315923d8 | ||
|
|
3d3228fe96 | ||
|
|
173ac5a8aa | ||
|
|
e9c5d7e7cf | ||
|
|
194127dce9 | ||
|
|
86cb7e9d41 | ||
|
|
b2774de6a2 | ||
|
|
3a4722b701 | ||
|
|
028aea4e3d | ||
|
|
c3dd97a7c1 | ||
|
|
d527fcdd78 | ||
|
|
d6f311e057 | ||
|
|
991e08fa71 | ||
|
|
06b44dc101 | ||
|
|
2d94b994fa | ||
|
|
c036186dde | ||
|
|
bc2ad13037 | ||
|
|
bfa04856aa | ||
|
|
feb1068441 | ||
|
|
181a4d05b0 | ||
|
|
c449265e05 | ||
|
|
e778616b5c | ||
|
|
dad5be2670 | ||
|
|
414afd17b8 | ||
|
|
86a806bca2 | ||
|
|
faed7420a7 | ||
|
|
ae14ff4f9f | ||
|
|
99e1658fdf | ||
|
|
e79264eefc | ||
|
|
dd0e26e7bc | ||
|
|
342c4bfbc2 | ||
|
|
7d2b8fd4c8 | ||
|
|
6426622992 | ||
|
|
3d154411de | ||
|
|
241f41e900 | ||
|
|
6c3d24d895 | ||
|
|
b2a0204f6b | ||
|
|
a9d71652b7 | ||
|
|
1b6bfb33d6 | ||
|
|
aec0d8d681 | ||
|
|
e38871b52d | ||
|
|
c1b4551dd1 | ||
|
|
d479140f87 |
@@ -27,10 +27,11 @@ func main() {
|
||||
app.Version(teaconst.Version)
|
||||
app.Product(teaconst.ProductName)
|
||||
app.Usage(teaconst.ProcessName + " [start|stop|restart|setup|upgrade|service|daemon|issues]")
|
||||
|
||||
app.On("setup", func() {
|
||||
var setupCmd = setup.NewSetupFromCmd()
|
||||
err := setupCmd.Run()
|
||||
result := maps.Map{}
|
||||
var result = maps.Map{}
|
||||
if err != nil {
|
||||
result["isOk"] = false
|
||||
result["error"] = err.Error()
|
||||
|
||||
@@ -18,7 +18,7 @@ func main() {
|
||||
fmt.Println("[ERROR]" + err.Error())
|
||||
return
|
||||
}
|
||||
results, err := setup.NewSQLDump().Dump(db)
|
||||
results, err := setup.NewSQLDump().Dump(db, true)
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]" + err.Error())
|
||||
return
|
||||
|
||||
@@ -5,12 +5,18 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DNSProvider struct {
|
||||
raw dnsclients.ProviderInterface
|
||||
dnsDomain string
|
||||
|
||||
locker sync.Mutex
|
||||
deletedRecordNames []string
|
||||
}
|
||||
|
||||
func NewDNSProvider(raw dnsclients.ProviderInterface, dnsDomain string) *DNSProvider {
|
||||
@@ -21,6 +27,7 @@ func NewDNSProvider(raw dnsclients.ProviderInterface, dnsDomain string) *DNSProv
|
||||
}
|
||||
|
||||
func (this *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true")
|
||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||
|
||||
// 设置记录
|
||||
@@ -29,31 +36,38 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
return errors.New("invalid fqdn value")
|
||||
}
|
||||
var recordName = fqdn[:index]
|
||||
record, err := this.raw.QueryRecord(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
|
||||
if err != nil {
|
||||
return errors.New("query DNS record failed: " + err.Error())
|
||||
|
||||
// 先删除老的
|
||||
this.locker.Lock()
|
||||
var wasDeleted = lists.ContainsString(this.deletedRecordNames, recordName)
|
||||
this.locker.Unlock()
|
||||
|
||||
if !wasDeleted {
|
||||
records, err := this.raw.QueryRecords(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
|
||||
if err != nil {
|
||||
return errors.New("query DNS record failed: " + err.Error())
|
||||
}
|
||||
for _, record := range records {
|
||||
err = this.raw.DeleteRecord(this.dnsDomain, record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
this.locker.Lock()
|
||||
this.deletedRecordNames = append(this.deletedRecordNames, recordName)
|
||||
this.locker.Unlock()
|
||||
}
|
||||
if record == nil {
|
||||
err = this.raw.AddRecord(this.dnsDomain, &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: recordName,
|
||||
Type: dnstypes.RecordTypeTXT,
|
||||
Value: value,
|
||||
Route: this.raw.DefaultRoute(),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.New("create DNS record failed: " + err.Error())
|
||||
}
|
||||
} else {
|
||||
err = this.raw.UpdateRecord(this.dnsDomain, record, &dnstypes.Record{
|
||||
Name: recordName,
|
||||
Type: dnstypes.RecordTypeTXT,
|
||||
Value: value,
|
||||
Route: this.raw.DefaultRoute(),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.New("update DNS record failed: " + err.Error())
|
||||
}
|
||||
|
||||
// 添加新的
|
||||
err := this.raw.AddRecord(this.dnsDomain, &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: recordName,
|
||||
Type: dnstypes.RecordTypeTXT,
|
||||
Value: value,
|
||||
Route: this.raw.DefaultRoute(),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.New("create DNS record failed: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.5.7"
|
||||
Version = "0.5.8"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,13 +18,8 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "0.5.6"
|
||||
UserNodeVersion = "0.5.6"
|
||||
DNSNodeVersion = "0.2.8"
|
||||
AuthorityNodeVersion = "0.0.2"
|
||||
MonitorNodeVersion = "0.0.4"
|
||||
ReportNodeVersion = "0.1.1"
|
||||
NodeVersion = "0.5.8"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
SQLVersion = "2"
|
||||
SQLVersion = "4"
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 生成日志
|
||||
// CreateACMETaskLog 生成日志
|
||||
func (this *ACMETaskLogDAO) CreateACMETaskLog(tx *dbs.Tx, taskId int64, isOk bool, errMsg string) error {
|
||||
var op = NewACMETaskLogOperator()
|
||||
op.TaskId = taskId
|
||||
@@ -37,7 +37,7 @@ func (this *ACMETaskLogDAO) CreateACMETaskLog(tx *dbs.Tx, taskId int64, isOk boo
|
||||
return err
|
||||
}
|
||||
|
||||
// 取得任务的最后一条执行日志
|
||||
// FindLatestACMETasKLog 取得任务的最后一条执行日志
|
||||
func (this *ACMETaskLogDAO) FindLatestACMETasKLog(tx *dbs.Tx, taskId int64) (*ACMETaskLog, error) {
|
||||
one, err := this.Query(tx).
|
||||
Attr("taskId", taskId).
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/ttlcache"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"strconv"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -13,7 +17,20 @@ const (
|
||||
ClientBrowserStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
var clientBrowserNameAndIdCacheMap = map[string]int64{}
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
// 清理数据任务
|
||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
err := SharedClientBrowserDAO.Clean(nil, 7) // 只保留N天
|
||||
if err != nil {
|
||||
remotelogs.Error("SharedClientBrowserDAO", "clean expired data failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type ClientBrowserDAO dbs.DAO
|
||||
|
||||
@@ -74,65 +91,64 @@ func (this *ClientBrowserDAO) FindClientBrowserName(tx *dbs.Tx, id uint32) (stri
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindBrowserIdWithNameCacheable 根据浏览器名称查找浏览器ID
|
||||
func (this *ClientBrowserDAO) FindBrowserIdWithNameCacheable(tx *dbs.Tx, browserName string) (int64, error) {
|
||||
SharedCacheLocker.RLock()
|
||||
browserId, ok := clientBrowserNameAndIdCacheMap[browserName]
|
||||
if ok {
|
||||
SharedCacheLocker.RUnlock()
|
||||
return browserId, nil
|
||||
}
|
||||
SharedCacheLocker.RUnlock()
|
||||
|
||||
browserId, err := this.Query(tx).
|
||||
Where("JSON_CONTAINS(codes, :browserName)").
|
||||
Param("browserName", strconv.Quote(browserName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if browserId > 0 {
|
||||
// 只有找到的时候才放入缓存,以便于我们可以在不存在的时候创建一条新的记录
|
||||
SharedCacheLocker.Lock()
|
||||
clientBrowserNameAndIdCacheMap[browserName] = browserId
|
||||
SharedCacheLocker.Unlock()
|
||||
}
|
||||
|
||||
return browserId, nil
|
||||
}
|
||||
|
||||
// CreateBrowser 创建浏览器
|
||||
func (this *ClientBrowserDAO) CreateBrowser(tx *dbs.Tx, browserName string) (int64, error) {
|
||||
var maxlength = 50
|
||||
// CreateBrowserIfNotExists 创建浏览器信息
|
||||
func (this *ClientBrowserDAO) CreateBrowserIfNotExists(tx *dbs.Tx, browserName string) error {
|
||||
const maxlength = 50
|
||||
if len(browserName) > maxlength {
|
||||
browserName = browserName[:50]
|
||||
}
|
||||
|
||||
SharedCacheLocker.Lock()
|
||||
defer SharedCacheLocker.Unlock()
|
||||
// 检查缓存
|
||||
var cacheKey = "clientBrowser:" + browserName
|
||||
var cacheItem = ttlcache.SharedCache.Read(cacheKey)
|
||||
if cacheItem != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否已经创建
|
||||
// 检查是否已经存在
|
||||
// 不需要加状态条件
|
||||
browserId, err := this.Query(tx).
|
||||
Attr("name", browserName).
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return err
|
||||
}
|
||||
if browserId > 0 {
|
||||
return browserId, nil
|
||||
// 加入缓存,但缓存时间不要过长,因为有别的操作在更新数据
|
||||
ttlcache.SharedCache.Write(cacheKey, browserId, time.Now().Unix()+3600)
|
||||
|
||||
return this.Query(tx).
|
||||
Pk(browserId).
|
||||
Set("createdDay", timeutil.Format("Ymd")).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// 如果不存在,则创建之
|
||||
var op = NewClientBrowserOperator()
|
||||
op.Name = browserName
|
||||
codes := []string{browserName}
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
op.CreatedDay = timeutil.Format("Ymd")
|
||||
op.State = ClientBrowserStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
browserId, err = this.SaveInt64(tx, op)
|
||||
if err != nil && CheckSQLErrCode(err, 1062 /** duplicate entry **/) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 加入缓存,但缓存时间不要过长,因为有别的操作在更新数据
|
||||
if browserId > 0 {
|
||||
ttlcache.SharedCache.Write(cacheKey, browserId, time.Now().Unix()+3600)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Clean 清理
|
||||
func (this *ClientBrowserDAO) Clean(tx *dbs.Tx, days int) error {
|
||||
if days <= 0 {
|
||||
days = 30
|
||||
}
|
||||
|
||||
return this.Query(tx).
|
||||
Lt("createdDay", timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))).
|
||||
DeleteQuickly()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
package models
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClientBrowserDAO_CreateBrowser(t *testing.T) {
|
||||
var dao = models.NewClientBrowserDAO()
|
||||
err := dao.CreateBrowserIfNotExists(nil, "Hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dao.CreateBrowserIfNotExists(nil, "Hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dao.CreateBrowserIfNotExists(nil, "Hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientBrowserDAO_Clean(t *testing.T) {
|
||||
var dao = models.NewClientBrowserDAO()
|
||||
err := dao.Clean(nil, 30)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,19 @@ import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// ClientBrowser 终端浏览器信息
|
||||
type ClientBrowser struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 浏览器名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 浏览器名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
CreatedDay string `field:"createdDay"` // 创建日期YYYYMMDD
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type ClientBrowserOperator struct {
|
||||
Id interface{} // ID
|
||||
Name interface{} // 浏览器名称
|
||||
Codes interface{} // 代号
|
||||
State interface{} // 状态
|
||||
Id any // ID
|
||||
Name any // 浏览器名称
|
||||
Codes any // 代号
|
||||
CreatedDay any // 创建日期YYYYMMDD
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewClientBrowserOperator() *ClientBrowserOperator {
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/ttlcache"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"strconv"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -13,7 +17,20 @@ const (
|
||||
ClientSystemStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
var clientSystemNameAndIdCacheMap = map[string]int64{} // system name => id
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
// 清理数据任务
|
||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
err := SharedClientSystemDAO.Clean(nil, 7) // 只保留N天
|
||||
if err != nil {
|
||||
remotelogs.Error("SharedClientSystemDAO", "clean expired data failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type ClientSystemDAO dbs.DAO
|
||||
|
||||
@@ -74,67 +91,63 @@ func (this *ClientSystemDAO) FindClientSystemName(tx *dbs.Tx, id uint32) (string
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindSystemIdWithNameCacheable 根据操作系统名称查找系统ID
|
||||
func (this *ClientSystemDAO) FindSystemIdWithNameCacheable(tx *dbs.Tx, systemName string) (int64, error) {
|
||||
SharedCacheLocker.RLock()
|
||||
systemId, ok := clientSystemNameAndIdCacheMap[systemName]
|
||||
if ok {
|
||||
SharedCacheLocker.RUnlock()
|
||||
return systemId, nil
|
||||
}
|
||||
SharedCacheLocker.RUnlock()
|
||||
|
||||
systemId, err := this.Query(tx).
|
||||
Where("JSON_CONTAINS(codes, :systemName)").
|
||||
Param("systemName", strconv.Quote(systemName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if systemId > 0 {
|
||||
// 只有找到的时候才放入缓存,以便于我们可以在不存在的时候创建一条新的记录
|
||||
SharedCacheLocker.Lock()
|
||||
clientSystemNameAndIdCacheMap[systemName] = systemId
|
||||
SharedCacheLocker.Unlock()
|
||||
}
|
||||
|
||||
return systemId, nil
|
||||
}
|
||||
|
||||
// CreateSystem 创建浏览器
|
||||
func (this *ClientSystemDAO) CreateSystem(tx *dbs.Tx, systemName string) (int64, error) {
|
||||
var maxlength = 50
|
||||
// CreateSystemIfNotExists 创建系统信息
|
||||
func (this *ClientSystemDAO) CreateSystemIfNotExists(tx *dbs.Tx, systemName string) error {
|
||||
const maxlength = 50
|
||||
if len(systemName) > maxlength {
|
||||
systemName = systemName[:50]
|
||||
}
|
||||
|
||||
SharedCacheLocker.Lock()
|
||||
defer SharedCacheLocker.Unlock()
|
||||
// 检查缓存
|
||||
var cacheKey = "clientSystem:" + systemName
|
||||
var cacheItem = ttlcache.SharedCache.Read(cacheKey)
|
||||
if cacheItem != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否已经创建
|
||||
// 检查是否已经存在
|
||||
// 不需要加状态条件
|
||||
systemId, err := this.Query(tx).
|
||||
Attr("name", systemName).
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return err
|
||||
}
|
||||
if systemId > 0 {
|
||||
return systemId, nil
|
||||
// 加入缓存,但缓存时间不要过长,因为有别的操作在更新数据
|
||||
ttlcache.SharedCache.Write(cacheKey, systemId, time.Now().Unix()+3600)
|
||||
|
||||
return this.Query(tx).
|
||||
Pk(systemId).
|
||||
Set("createdDay", timeutil.Format("Ymd")).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
var op = NewClientSystemOperator()
|
||||
op.Name = systemName
|
||||
|
||||
codes := []string{systemName}
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
|
||||
op.CreatedDay = timeutil.Format("Ymd")
|
||||
op.State = ClientSystemStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
systemId, err = this.SaveInt64(tx, op)
|
||||
if err != nil && CheckSQLErrCode(err, 1062 /** duplicate entry **/) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 加入缓存,但缓存时间不要过长,因为有别的操作在更新数据
|
||||
if systemId > 0 {
|
||||
ttlcache.SharedCache.Write(cacheKey, systemId, time.Now().Unix()+3600)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Clean 清理
|
||||
func (this *ClientSystemDAO) Clean(tx *dbs.Tx, days int) error {
|
||||
if days <= 0 {
|
||||
days = 30
|
||||
}
|
||||
|
||||
return this.Query(tx).
|
||||
Lt("createdDay", timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))).
|
||||
DeleteQuickly()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
package models
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClientSystemDAO_CreateSystemIfNotExists(t *testing.T) {
|
||||
var dao = models.NewClientSystemDAO()
|
||||
{
|
||||
err := dao.CreateSystemIfNotExists(nil, "Mac OS X")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
{
|
||||
err := dao.CreateSystemIfNotExists(nil, "Mac OS X 2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSystemDAO_Clean(t *testing.T) {
|
||||
var dao = models.NewClientSystemDAO()
|
||||
err := dao.Clean(nil, 30)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,19 @@ import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// ClientSystem 终端操作系统信息
|
||||
type ClientSystem struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 系统名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
State uint8 `field:"state"` //
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 系统名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
CreatedDay string `field:"createdDay"` // 创建日期YYYYMMDD
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type ClientSystemOperator struct {
|
||||
Id interface{} // ID
|
||||
Name interface{} // 系统名称
|
||||
Codes interface{} // 代号
|
||||
State interface{} //
|
||||
Id any // ID
|
||||
Name any // 系统名称
|
||||
Codes any // 代号
|
||||
CreatedDay any // 创建日期YYYYMMDD
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewClientSystemOperator() *ClientSystemOperator {
|
||||
|
||||
@@ -78,8 +78,8 @@ func (this *DNSTaskDAO) CreateClusterRemoveTask(tx *dbs.Tx, clusterId int64, dom
|
||||
}
|
||||
|
||||
// CreateNodeTask 生成节点任务
|
||||
func (this *DNSTaskDAO) CreateNodeTask(tx *dbs.Tx, nodeId int64, taskType DNSTaskType) error {
|
||||
return this.CreateDNSTask(tx, 0, 0, nodeId, 0, "", taskType)
|
||||
func (this *DNSTaskDAO) CreateNodeTask(tx *dbs.Tx, clusterId int64, nodeId int64, taskType DNSTaskType) error {
|
||||
return this.CreateDNSTask(tx, clusterId, 0, nodeId, 0, "", taskType)
|
||||
}
|
||||
|
||||
// CreateServerTask 生成服务任务
|
||||
|
||||
207
internal/db/models/formal_client_browser_dao.go
Normal file
207
internal/db/models/formal_client_browser_dao.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/ttlcache"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
FormalClientBrowserStateEnabled = 1 // 已启用
|
||||
FormalClientBrowserStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type FormalClientBrowserDAO dbs.DAO
|
||||
|
||||
func NewFormalClientBrowserDAO() *FormalClientBrowserDAO {
|
||||
return dbs.NewDAO(&FormalClientBrowserDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeFormalClientBrowsers",
|
||||
Model: new(FormalClientBrowser),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*FormalClientBrowserDAO)
|
||||
}
|
||||
|
||||
var SharedFormalClientBrowserDAO *FormalClientBrowserDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedFormalClientBrowserDAO = NewFormalClientBrowserDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableFormalClientBrowser 启用条目
|
||||
func (this *FormalClientBrowserDAO) EnableFormalClientBrowser(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", FormalClientBrowserStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableFormalClientBrowser 禁用条目
|
||||
func (this *FormalClientBrowserDAO) DisableFormalClientBrowser(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", FormalClientBrowserStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledFormalClientBrowser 查找启用中的条目
|
||||
func (this *FormalClientBrowserDAO) FindEnabledFormalClientBrowser(tx *dbs.Tx, id int64) (*FormalClientBrowser, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
State(FormalClientBrowserStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*FormalClientBrowser), err
|
||||
}
|
||||
|
||||
// FindFormalClientBrowserName 根据主键查找名称
|
||||
func (this *FormalClientBrowserDAO) FindFormalClientBrowserName(tx *dbs.Tx, id uint32) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindBrowserIdWithNameCacheable 根据浏览器名称查找系统ID
|
||||
func (this *FormalClientBrowserDAO) FindBrowserIdWithNameCacheable(tx *dbs.Tx, browserName string) (int64, error) {
|
||||
var cacheKey = "formalClientBrowser:" + browserName
|
||||
var cacheItem = ttlcache.SharedCache.Read(cacheKey)
|
||||
if cacheItem != nil {
|
||||
return types.Int64(cacheItem.Value), nil
|
||||
}
|
||||
|
||||
// 先使用 name 查找,因为有索引,所以会快一些
|
||||
browserId, err := this.Query(tx).
|
||||
Attr("name", browserName).
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if browserId == 0 {
|
||||
browserId, err = this.Query(tx).
|
||||
Where("JSON_CONTAINS(codes, :browserName)").
|
||||
Param("browserName", strconv.Quote(browserName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// 即使找不到也要放入到缓存中
|
||||
ttlcache.SharedCache.Write(cacheKey, browserId, time.Now().Unix()+3600)
|
||||
|
||||
return browserId, nil
|
||||
}
|
||||
|
||||
// CountBrowsers 计算浏览器数量
|
||||
func (this *FormalClientBrowserDAO) CountBrowsers(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Like("LOWER(codes)", dbutils.QuoteLikeKeyword(strings.ToLower(keyword)))
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListBrowsers 列出单页浏览器信息
|
||||
func (this *FormalClientBrowserDAO) ListBrowsers(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*FormalClientBrowser, err error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Like("LOWER(codes)", dbutils.QuoteLikeKeyword(strings.ToLower(keyword)))
|
||||
}
|
||||
_, err = query.
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindBrowserWithDataId 根据dataId查找浏览器信息
|
||||
func (this *FormalClientBrowserDAO) FindBrowserWithDataId(tx *dbs.Tx, dataId string) (*FormalClientBrowser, error) {
|
||||
one, err := this.Query(tx).
|
||||
Attr("dataId", dataId).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*FormalClientBrowser), nil
|
||||
}
|
||||
|
||||
// CreateBrowser 创建浏览器信息
|
||||
func (this *FormalClientBrowserDAO) CreateBrowser(tx *dbs.Tx, name string, codes []string, dataId string) (int64, error) {
|
||||
if len(dataId) == 0 {
|
||||
return 0, errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
// 检查 dataId 是否已经存在
|
||||
exists, err := this.Query(tx).
|
||||
Attr("dataId", dataId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if exists {
|
||||
return 0, errors.New("dataId '" + dataId + "' already exists")
|
||||
}
|
||||
|
||||
var op = NewFormalClientBrowserOperator()
|
||||
op.Name = name
|
||||
if len(codes) == 0 {
|
||||
op.Codes = "[]"
|
||||
} else {
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
}
|
||||
op.DataId = dataId
|
||||
op.State = FormalClientBrowserStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// UpdateBrowser 修改浏览器信息
|
||||
func (this *FormalClientBrowserDAO) UpdateBrowser(tx *dbs.Tx, browserId int64, name string, codes []string, dataId string) error {
|
||||
if browserId <= 0 {
|
||||
return errors.New("invalid browserId '" + types.String(browserId) + "'")
|
||||
}
|
||||
if len(dataId) == 0 {
|
||||
return errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
var op = NewFormalClientBrowserOperator()
|
||||
op.Id = browserId
|
||||
op.Name = name
|
||||
if len(codes) == 0 {
|
||||
op.Codes = "[]"
|
||||
} else {
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
}
|
||||
op.DataId = dataId
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
6
internal/db/models/formal_client_browser_dao_test.go
Normal file
6
internal/db/models/formal_client_browser_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
24
internal/db/models/formal_client_browser_model.go
Normal file
24
internal/db/models/formal_client_browser_model.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// FormalClientBrowser 终端浏览器信息
|
||||
type FormalClientBrowser struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 浏览器名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
DataId string `field:"dataId"` // 数据ID
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type FormalClientBrowserOperator struct {
|
||||
Id any // ID
|
||||
Name any // 浏览器名称
|
||||
Codes any // 代号
|
||||
DataId any // 数据ID
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewFormalClientBrowserOperator() *FormalClientBrowserOperator {
|
||||
return &FormalClientBrowserOperator{}
|
||||
}
|
||||
21
internal/db/models/formal_client_browser_model_ext.go
Normal file
21
internal/db/models/formal_client_browser_model_ext.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
)
|
||||
|
||||
// DecodeCodes 解析代号
|
||||
func (this *FormalClientBrowser) DecodeCodes() []string {
|
||||
if IsNull(this.Codes) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
err := json.Unmarshal(this.Codes, &result)
|
||||
if err != nil {
|
||||
remotelogs.Error("FormalClientBrowser.DecodeCodes", err.Error())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
207
internal/db/models/formal_client_system_dao.go
Normal file
207
internal/db/models/formal_client_system_dao.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/ttlcache"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
FormalClientSystemStateEnabled = 1 // 已启用
|
||||
FormalClientSystemStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type FormalClientSystemDAO dbs.DAO
|
||||
|
||||
func NewFormalClientSystemDAO() *FormalClientSystemDAO {
|
||||
return dbs.NewDAO(&FormalClientSystemDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeFormalClientSystems",
|
||||
Model: new(FormalClientSystem),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*FormalClientSystemDAO)
|
||||
}
|
||||
|
||||
var SharedFormalClientSystemDAO *FormalClientSystemDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedFormalClientSystemDAO = NewFormalClientSystemDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableFormalClientSystem 启用条目
|
||||
func (this *FormalClientSystemDAO) EnableFormalClientSystem(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", FormalClientSystemStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableFormalClientSystem 禁用条目
|
||||
func (this *FormalClientSystemDAO) DisableFormalClientSystem(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", FormalClientSystemStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledFormalClientSystem 查找启用中的条目
|
||||
func (this *FormalClientSystemDAO) FindEnabledFormalClientSystem(tx *dbs.Tx, id int64) (*FormalClientSystem, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
State(FormalClientSystemStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*FormalClientSystem), err
|
||||
}
|
||||
|
||||
// FindFormalClientSystemName 根据主键查找名称
|
||||
func (this *FormalClientSystemDAO) FindFormalClientSystemName(tx *dbs.Tx, id uint32) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindSystemIdWithNameCacheable 根据操作系统名称查找系统ID
|
||||
func (this *FormalClientSystemDAO) FindSystemIdWithNameCacheable(tx *dbs.Tx, systemName string) (int64, error) {
|
||||
var cacheKey = "formalClientSystem:" + systemName
|
||||
var cacheItem = ttlcache.SharedCache.Read(cacheKey)
|
||||
if cacheItem != nil {
|
||||
return types.Int64(cacheItem.Value), nil
|
||||
}
|
||||
|
||||
// 先使用 name 查找,因为有索引,所以会快一些
|
||||
systemId, err := this.Query(tx).
|
||||
Attr("name", systemName).
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if systemId == 0 {
|
||||
systemId, err = this.Query(tx).
|
||||
Where("JSON_CONTAINS(codes, :systemName)").
|
||||
Param("systemName", strconv.Quote(systemName)). // 查询的需要是个JSON字符串,所以这里加双引号
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// 即使找不到也要放入到缓存中
|
||||
ttlcache.SharedCache.Write(cacheKey, systemId, time.Now().Unix()+3600)
|
||||
|
||||
return systemId, nil
|
||||
}
|
||||
|
||||
// CreateSystem 创建操作系统信息
|
||||
func (this *FormalClientSystemDAO) CreateSystem(tx *dbs.Tx, name string, codes []string, dataId string) (int64, error) {
|
||||
if len(dataId) == 0 {
|
||||
return 0, errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
// 检查 dataId 是否已经存在
|
||||
exists, err := this.Query(tx).
|
||||
Attr("dataId", dataId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if exists {
|
||||
return 0, errors.New("dataId '" + dataId + "' already exists")
|
||||
}
|
||||
|
||||
var op = NewFormalClientSystemOperator()
|
||||
op.Name = name
|
||||
if len(codes) == 0 {
|
||||
op.Codes = "[]"
|
||||
} else {
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
}
|
||||
op.DataId = dataId
|
||||
op.State = FormalClientSystemStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// UpdateSystem 修改操作系统信息
|
||||
func (this *FormalClientSystemDAO) UpdateSystem(tx *dbs.Tx, systemId int64, name string, codes []string, dataId string) error {
|
||||
if systemId <= 0 {
|
||||
return errors.New("invalid systemId '" + types.String(systemId) + "'")
|
||||
}
|
||||
if len(dataId) == 0 {
|
||||
return errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
var op = NewFormalClientSystemOperator()
|
||||
op.Id = systemId
|
||||
op.Name = name
|
||||
if len(codes) == 0 {
|
||||
op.Codes = "[]"
|
||||
} else {
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.Codes = codesJSON
|
||||
}
|
||||
op.DataId = dataId
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
// CountSystems 计算操作系统数量
|
||||
func (this *FormalClientSystemDAO) CountSystems(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Like("LOWER(codes)", dbutils.QuoteLikeKeyword(strings.ToLower(keyword)))
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListSystems 列出单页操作系统信息
|
||||
func (this *FormalClientSystemDAO) ListSystems(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*FormalClientSystem, err error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Like("LOWER(codes)", dbutils.QuoteLikeKeyword(strings.ToLower(keyword)))
|
||||
}
|
||||
_, err = query.
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindSystemWithDataId 根据dataId查找操作系统信息
|
||||
func (this *FormalClientSystemDAO) FindSystemWithDataId(tx *dbs.Tx, dataId string) (*FormalClientSystem, error) {
|
||||
one, err := this.Query(tx).
|
||||
Attr("dataId", dataId).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*FormalClientSystem), nil
|
||||
}
|
||||
6
internal/db/models/formal_client_system_dao_test.go
Normal file
6
internal/db/models/formal_client_system_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
24
internal/db/models/formal_client_system_model.go
Normal file
24
internal/db/models/formal_client_system_model.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// FormalClientSystem 终端操作系统信息
|
||||
type FormalClientSystem struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 系统名称
|
||||
Codes dbs.JSON `field:"codes"` // 代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
DataId string `field:"dataId"` // 数据ID
|
||||
}
|
||||
|
||||
type FormalClientSystemOperator struct {
|
||||
Id any // ID
|
||||
Name any // 系统名称
|
||||
Codes any // 代号
|
||||
State any // 状态
|
||||
DataId any // 数据ID
|
||||
}
|
||||
|
||||
func NewFormalClientSystemOperator() *FormalClientSystemOperator {
|
||||
return &FormalClientSystemOperator{}
|
||||
}
|
||||
21
internal/db/models/formal_client_system_model_ext.go
Normal file
21
internal/db/models/formal_client_system_model_ext.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
)
|
||||
|
||||
// DecodeCodes 解析代号
|
||||
func (this *FormalClientSystem) DecodeCodes() []string {
|
||||
if IsNull(this.Codes) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
err := json.Unmarshal(this.Codes, &result)
|
||||
if err != nil {
|
||||
remotelogs.Error("FormalClientSystem.DecodeCodes", err.Error())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -460,6 +460,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
|
||||
var requestPathReg = regexp.MustCompile(`requestPath:(\S+)`)
|
||||
var protoReg = regexp.MustCompile(`proto:(\S+)`)
|
||||
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
|
||||
var methodReg = regexp.MustCompile(`(?:method|requestMethod):(\S+)`)
|
||||
|
||||
var count = len(tableQueries)
|
||||
var wg = &sync.WaitGroup{}
|
||||
@@ -607,6 +608,11 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
|
||||
query.Where("JSON_EXTRACT(content, '$.requestURI') LIKE :keyword").
|
||||
Param("keyword", dbutils.QuoteLikePrefix("\""+u.RequestURI()))
|
||||
}
|
||||
} else if methodReg.MatchString(keyword) { // method|requestMethod:xxx
|
||||
isSpecialKeyword = true
|
||||
var matches = methodReg.FindStringSubmatch(keyword)
|
||||
query.Where("JSON_EXTRACT(content, '$.requestMethod')=:keyword").
|
||||
Param("keyword", strings.ToUpper(matches[1]))
|
||||
}
|
||||
if !isSpecialKeyword {
|
||||
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
|
||||
|
||||
73
internal/db/models/nameservers/ns_record_dao.go
Normal file
73
internal/db/models/nameservers/ns_record_dao.go
Normal file
@@ -0,0 +1,73 @@
|
||||
//go:build !plus
|
||||
|
||||
package nameservers
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
NSRecordStateEnabled = 1 // 已启用
|
||||
NSRecordStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type NSRecordDAO dbs.DAO
|
||||
|
||||
func NewNSRecordDAO() *NSRecordDAO {
|
||||
return dbs.NewDAO(&NSRecordDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeNSRecords",
|
||||
Model: new(NSRecord),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*NSRecordDAO)
|
||||
}
|
||||
|
||||
var SharedNSRecordDAO *NSRecordDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedNSRecordDAO = NewNSRecordDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableNSRecord 启用条目
|
||||
func (this *NSRecordDAO) EnableNSRecord(tx *dbs.Tx, id uint64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", NSRecordStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableNSRecord 禁用条目
|
||||
func (this *NSRecordDAO) DisableNSRecord(tx *dbs.Tx, id uint64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", NSRecordStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledNSRecord 查找启用中的条目
|
||||
func (this *NSRecordDAO) FindEnabledNSRecord(tx *dbs.Tx, id uint64) (*NSRecord, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
State(NSRecordStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*NSRecord), err
|
||||
}
|
||||
|
||||
// FindNSRecordName 根据主键查找名称
|
||||
func (this *NSRecordDAO) FindNSRecordName(tx *dbs.Tx, id uint64) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
6
internal/db/models/nameservers/ns_record_dao_test.go
Normal file
6
internal/db/models/nameservers/ns_record_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package nameservers_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -11,28 +11,30 @@ type NSRecord struct {
|
||||
Name string `field:"name"` // 记录名
|
||||
Type string `field:"type"` // 类型
|
||||
Value string `field:"value"` // 值
|
||||
MxPriority uint32 `field:"mxPriority"` // MX优先级
|
||||
Ttl uint32 `field:"ttl"` // TTL(秒)
|
||||
Weight uint32 `field:"weight"` // 权重
|
||||
RouteIds dbs.JSON `field:"routeIds"` // 线路
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
Version uint64 `field:"version"` //
|
||||
Version uint64 `field:"version"` // 版本号
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type NSRecordOperator struct {
|
||||
Id interface{} // ID
|
||||
DomainId interface{} // 域名ID
|
||||
IsOn interface{} // 是否启用
|
||||
Description interface{} // 备注
|
||||
Name interface{} // 记录名
|
||||
Type interface{} // 类型
|
||||
Value interface{} // 值
|
||||
Ttl interface{} // TTL(秒)
|
||||
Weight interface{} // 权重
|
||||
RouteIds interface{} // 线路
|
||||
CreatedAt interface{} // 创建时间
|
||||
Version interface{} //
|
||||
State interface{} // 状态
|
||||
Id any // ID
|
||||
DomainId any // 域名ID
|
||||
IsOn any // 是否启用
|
||||
Description any // 备注
|
||||
Name any // 记录名
|
||||
Type any // 类型
|
||||
Value any // 值
|
||||
MxPriority any // MX优先级
|
||||
Ttl any // TTL(秒)
|
||||
Weight any // 权重
|
||||
RouteIds any // 线路
|
||||
CreatedAt any // 创建时间
|
||||
Version any // 版本号
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewNSRecordOperator() *NSRecordOperator {
|
||||
|
||||
33
internal/db/models/nameservers/ns_route_category_dao.go
Normal file
33
internal/db/models/nameservers/ns_route_category_dao.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package nameservers
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
NSRouteCategoryStateEnabled = 1 // 已启用
|
||||
NSRouteCategoryStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type NSRouteCategoryDAO dbs.DAO
|
||||
|
||||
func NewNSRouteCategoryDAO() *NSRouteCategoryDAO {
|
||||
return dbs.NewDAO(&NSRouteCategoryDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeNSRouteCategories",
|
||||
Model: new(NSRouteCategory),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*NSRouteCategoryDAO)
|
||||
}
|
||||
|
||||
var SharedNSRouteCategoryDAO *NSRouteCategoryDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedNSRouteCategoryDAO = NewNSRouteCategoryDAO()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package nameservers_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
26
internal/db/models/nameservers/ns_route_category_model.go
Normal file
26
internal/db/models/nameservers/ns_route_category_model.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package nameservers
|
||||
|
||||
// NSRouteCategory 线路分类
|
||||
type NSRouteCategory struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 分类名
|
||||
AdminId uint64 `field:"adminId"` // 管理员ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
Order uint32 `field:"order"` // 排序
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type NSRouteCategoryOperator struct {
|
||||
Id any // ID
|
||||
IsOn any // 是否启用
|
||||
Name any // 分类名
|
||||
AdminId any // 管理员ID
|
||||
UserId any // 用户ID
|
||||
Order any // 排序
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewNSRouteCategoryOperator() *NSRouteCategoryOperator {
|
||||
return &NSRouteCategoryOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package nameservers
|
||||
73
internal/db/models/nameservers/ns_route_dao.go
Normal file
73
internal/db/models/nameservers/ns_route_dao.go
Normal file
@@ -0,0 +1,73 @@
|
||||
//go:build !plus
|
||||
|
||||
package nameservers
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
NSRouteStateEnabled = 1 // 已启用
|
||||
NSRouteStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type NSRouteDAO dbs.DAO
|
||||
|
||||
func NewNSRouteDAO() *NSRouteDAO {
|
||||
return dbs.NewDAO(&NSRouteDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeNSRoutes",
|
||||
Model: new(NSRoute),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*NSRouteDAO)
|
||||
}
|
||||
|
||||
var SharedNSRouteDAO *NSRouteDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedNSRouteDAO = NewNSRouteDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableNSRoute 启用条目
|
||||
func (this *NSRouteDAO) EnableNSRoute(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", NSRouteStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableNSRoute 禁用条目
|
||||
func (this *NSRouteDAO) DisableNSRoute(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", NSRouteStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledNSRoute 查找启用中的条目
|
||||
func (this *NSRouteDAO) FindEnabledNSRoute(tx *dbs.Tx, id uint32) (*NSRoute, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
State(NSRouteStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*NSRoute), err
|
||||
}
|
||||
|
||||
// FindNSRouteName 根据主键查找名称
|
||||
func (this *NSRouteDAO) FindNSRouteName(tx *dbs.Tx, id uint32) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
6
internal/db/models/nameservers/ns_route_dao_test.go
Normal file
6
internal/db/models/nameservers/ns_route_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package nameservers_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -4,31 +4,37 @@ import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// NSRoute DNS线路
|
||||
type NSRoute struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
DomainId uint32 `field:"domainId"` // 域名ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
Name string `field:"name"` // 名称
|
||||
Ranges dbs.JSON `field:"ranges"` // 范围
|
||||
Order uint32 `field:"order"` // 排序
|
||||
Version uint64 `field:"version"` // 版本号
|
||||
Code string `field:"code"` // 代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
CategoryId uint32 `field:"categoryId"` // 分类ID
|
||||
DomainId uint64 `field:"domainId"` // 域名ID
|
||||
AdminId uint64 `field:"adminId"` // 管理员ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
IsPublic bool `field:"isPublic"` // 是否公用(管理员创建的线路)
|
||||
Name string `field:"name"` // 名称
|
||||
Ranges dbs.JSON `field:"ranges"` // 范围
|
||||
Order uint32 `field:"order"` // 排序
|
||||
Version uint64 `field:"version"` // 版本号
|
||||
Code string `field:"code"` // 代号
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type NSRouteOperator struct {
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
ClusterId interface{} // 集群ID
|
||||
DomainId interface{} // 域名ID
|
||||
UserId interface{} // 用户ID
|
||||
Name interface{} // 名称
|
||||
Ranges interface{} // 范围
|
||||
Order interface{} // 排序
|
||||
Version interface{} // 版本号
|
||||
Code interface{} // 代号
|
||||
State interface{} // 状态
|
||||
Id any // ID
|
||||
IsOn any // 是否启用
|
||||
ClusterId any // 集群ID
|
||||
CategoryId any // 分类ID
|
||||
DomainId any // 域名ID
|
||||
AdminId any // 管理员ID
|
||||
UserId any // 用户ID
|
||||
IsPublic any // 是否公用(管理员创建的线路)
|
||||
Name any // 名称
|
||||
Ranges any // 范围
|
||||
Order any // 排序
|
||||
Version any // 版本号
|
||||
Code any // 代号
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewNSRouteOperator() *NSRouteOperator {
|
||||
|
||||
@@ -437,7 +437,7 @@ func (this *NodeClusterDAO) FindAllEnabledClustersWithDNSDomainId(tx *dbs.Tx, dn
|
||||
_, err = this.Query(tx).
|
||||
State(NodeClusterStateEnabled).
|
||||
Attr("dnsDomainId", dnsDomainId).
|
||||
Result("id", "name", "dnsName", "dnsDomainId", "isOn").
|
||||
Result("id", "name", "dnsName", "dnsDomainId", "isOn", "dns").
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
|
||||
@@ -961,6 +961,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
Level: types.Int32(node.Level),
|
||||
GroupId: int64(node.GroupId),
|
||||
EnableIPLists: node.EnableIPLists,
|
||||
APINodeAddrs: node.DecodeAPINodeAddrs(),
|
||||
}
|
||||
|
||||
// API节点IP
|
||||
@@ -1146,6 +1147,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
}
|
||||
|
||||
config.CacheDiskDir = node.CacheDiskDir
|
||||
config.CacheDiskSubDirs = node.DecodeCacheDiskSubDirs()
|
||||
|
||||
// TOA
|
||||
toaConfig, err := SharedNodeClusterDAO.FindClusterTOAConfig(tx, primaryClusterId, cacheMap)
|
||||
@@ -1621,7 +1623,7 @@ func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) er
|
||||
}
|
||||
|
||||
// UpdateNodeCache 设置缓存相关
|
||||
func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapacityJSON []byte, maxCacheMemoryCapacityJSON []byte, cacheDiskDir string) error {
|
||||
func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapacityJSON []byte, maxCacheMemoryCapacityJSON []byte, cacheDiskDir string, cacheDiskSubDirs []*serverconfigs.CacheDir) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
@@ -1634,7 +1636,17 @@ func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapac
|
||||
op.MaxCacheMemoryCapacity = maxCacheMemoryCapacityJSON
|
||||
}
|
||||
op.CacheDiskDir = cacheDiskDir
|
||||
err := this.Save(tx, op)
|
||||
|
||||
if cacheDiskSubDirs == nil {
|
||||
cacheDiskSubDirs = []*serverconfigs.CacheDir{}
|
||||
}
|
||||
cacheDiskSubDirsJSON, err := json.Marshal(cacheDiskSubDirs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.CacheDiskSubDirs = cacheDiskSubDirsJSON
|
||||
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1827,6 +1839,12 @@ func (this *NodeDAO) DeleteNodeFromCluster(tx *dbs.Tx, nodeId int64, clusterId i
|
||||
return nil
|
||||
}
|
||||
|
||||
// 提前通知DNS更新,因为后面集群会有变化
|
||||
err = this.NotifyDNSUpdate(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var node = one.(*Node)
|
||||
|
||||
var secondaryClusterIds = []int64{}
|
||||
@@ -2022,11 +2040,51 @@ func (this *NodeDAO) UpdateNodeDDoSProtection(tx *dbs.Tx, nodeId int64, ddosProt
|
||||
return err
|
||||
}
|
||||
if clusterId > 0 {
|
||||
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, 0, NodeTaskTypeDDosProtectionChanged, 0)
|
||||
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, 0, NodeTaskTypeDDosProtectionChanged)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindNodeAPIConfig 查找API相关配置信息
|
||||
func (this *NodeDAO) FindNodeAPIConfig(tx *dbs.Tx, nodeId int64) (*Node, error) {
|
||||
if nodeId <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
one, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("apiNodeAddrs").
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
return one.(*Node), nil
|
||||
}
|
||||
|
||||
// UpdateNodeAPIConfig 修改API相关配置信息
|
||||
func (this *NodeDAO) UpdateNodeAPIConfig(tx *dbs.Tx, nodeId int64, apiNodeAddrs []*serverconfigs.NetworkAddressConfig) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
|
||||
if apiNodeAddrs == nil {
|
||||
apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
}
|
||||
apiNodeAddrsJSON, err := json.Marshal(apiNodeAddrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var op = NewNodeOperator()
|
||||
op.Id = nodeId
|
||||
op.ApiNodeAddrs = apiNodeAddrsJSON
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return this.NotifyUpdate(tx, nodeId)
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知节点相关更新
|
||||
func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||
// 这里只需要通知单个集群即可,因为节点是公用的,更新一个就相当于更新了所有
|
||||
@@ -2034,7 +2092,7 @@ func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, 0, NodeTaskTypeConfigChanged, 0)
|
||||
err = SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2075,7 +2133,7 @@ func (this *NodeDAO) NotifyDNSUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||
if len(dnsInfo.DnsName) == 0 || dnsInfo.DnsDomainId <= 0 {
|
||||
continue
|
||||
}
|
||||
err = dns.SharedDNSTaskDAO.CreateNodeTask(tx, nodeId, dns.DNSTaskTypeNodeChange)
|
||||
err = dns.SharedDNSTaskDAO.CreateNodeTask(tx, clusterId, nodeId, dns.DNSTaskTypeNodeChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -604,7 +604,7 @@ func (this *NodeIPAddressDAO) NotifyUpdate(tx *dbs.Tx, addressId int64) error {
|
||||
var role = address.(*NodeIPAddress).Role
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
err = dns.SharedDNSTaskDAO.CreateNodeTask(tx, nodeId, dns.DNSTaskTypeNodeChange)
|
||||
err = dns.SharedDNSTaskDAO.CreateNodeTask(tx, 0, nodeId, dns.DNSTaskTypeNodeChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,9 +38,11 @@ type Node struct {
|
||||
DnsRoutes dbs.JSON `field:"dnsRoutes"` // DNS线路设置
|
||||
MaxCacheDiskCapacity dbs.JSON `field:"maxCacheDiskCapacity"` // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity dbs.JSON `field:"maxCacheMemoryCapacity"` // 内存缓存容量
|
||||
CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录
|
||||
CacheDiskDir string `field:"cacheDiskDir"` // 主缓存目录
|
||||
CacheDiskSubDirs dbs.JSON `field:"cacheDiskSubDirs"` // 其他缓存目录
|
||||
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
|
||||
EnableIPLists bool `field:"enableIPLists"` // 启用IP名单
|
||||
ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址
|
||||
}
|
||||
|
||||
type NodeOperator struct {
|
||||
@@ -78,9 +80,11 @@ type NodeOperator struct {
|
||||
DnsRoutes any // DNS线路设置
|
||||
MaxCacheDiskCapacity any // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity any // 内存缓存容量
|
||||
CacheDiskDir any // 缓存目录
|
||||
CacheDiskDir any // 主缓存目录
|
||||
CacheDiskSubDirs any // 其他缓存目录
|
||||
DnsResolver any // DNS解析器
|
||||
EnableIPLists any // 启用IP名单
|
||||
ApiNodeAddrs any // API节点地址
|
||||
}
|
||||
|
||||
func NewNodeOperator() *NodeOperator {
|
||||
|
||||
@@ -2,7 +2,9 @@ package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"sort"
|
||||
@@ -135,6 +137,7 @@ func (this *Node) HasDDoSProtection() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// DecodeMaxCacheDiskCapacity 解析硬盘容量
|
||||
func (this *Node) DecodeMaxCacheDiskCapacity() *shared.SizeCapacity {
|
||||
if this.MaxCacheDiskCapacity.IsNull() {
|
||||
return nil
|
||||
@@ -145,6 +148,7 @@ func (this *Node) DecodeMaxCacheDiskCapacity() *shared.SizeCapacity {
|
||||
return capacity
|
||||
}
|
||||
|
||||
// DecodeMaxCacheMemoryCapacity 解析内存容量
|
||||
func (this *Node) DecodeMaxCacheMemoryCapacity() *shared.SizeCapacity {
|
||||
if this.MaxCacheMemoryCapacity.IsNull() {
|
||||
return nil
|
||||
@@ -169,6 +173,7 @@ func (this *Node) DecodeDNSResolver() *nodeconfigs.DNSResolverConfig {
|
||||
return resolverConfig
|
||||
}
|
||||
|
||||
// DecodeLnAddrs 解析Ln地址
|
||||
func (this *Node) DecodeLnAddrs() []string {
|
||||
if IsNull(this.LnAddrs) {
|
||||
return nil
|
||||
@@ -181,3 +186,31 @@ func (this *Node) DecodeLnAddrs() []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DecodeCacheDiskSubDirs 解析缓存目录
|
||||
func (this *Node) DecodeCacheDiskSubDirs() []*serverconfigs.CacheDir {
|
||||
if IsNull(this.CacheDiskSubDirs) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []*serverconfigs.CacheDir{}
|
||||
err := json.Unmarshal(this.CacheDiskSubDirs, &result)
|
||||
if err != nil {
|
||||
remotelogs.Error("Node.DecodeCacheDiskSubDirs", err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DecodeAPINodeAddrs 解析API节点地址
|
||||
func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
|
||||
var result = []*serverconfigs.NetworkAddressConfig{}
|
||||
if IsNull(this.ApiNodeAddrs) {
|
||||
return result
|
||||
}
|
||||
|
||||
err := json.Unmarshal(this.ApiNodeAddrs, &result)
|
||||
if err != nil {
|
||||
remotelogs.Error("Node.DecodeAPINodeAddrs", err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func init() {
|
||||
}
|
||||
|
||||
// CreateNodeTask 创建单个节点任务
|
||||
func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64, nodeId int64, userId int64, serverId int64, taskType NodeTaskType, version int64) error {
|
||||
func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64, nodeId int64, userId int64, serverId int64, taskType NodeTaskType) error {
|
||||
if clusterId <= 0 || nodeId <= 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -69,8 +69,13 @@ func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64
|
||||
uniqueId += "@" + types.String(userId)
|
||||
}
|
||||
|
||||
version, err := this.increaseVersion(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var updatedAt = time.Now().Unix()
|
||||
_, _, err := this.Query(tx).
|
||||
_, _, err = this.Query(tx).
|
||||
InsertOrUpdate(maps.Map{
|
||||
"role": role,
|
||||
"clusterId": clusterId,
|
||||
@@ -157,9 +162,8 @@ func (this *NodeTaskDAO) ExtractNodeClusterTask(tx *dbs.Tx, clusterId int64, use
|
||||
return err
|
||||
}
|
||||
|
||||
var version = time.Now().UnixNano()
|
||||
for _, nodeId := range nodeIds {
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, userId, serverId, taskType, version)
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, userId, serverId, taskType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -225,14 +229,22 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
|
||||
}
|
||||
|
||||
// FindDoingNodeTasks 查询一个节点的所有任务
|
||||
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64) (result []*NodeTask, err error) {
|
||||
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) {
|
||||
if nodeId <= 0 {
|
||||
return
|
||||
}
|
||||
_, err = this.Query(tx).
|
||||
var query = this.Query(tx).
|
||||
Attr("role", role).
|
||||
Attr("nodeId", nodeId).
|
||||
Where("(isDone=0 OR (isDone=1 AND isOk=0))").
|
||||
Asc("version")
|
||||
if version > 0 {
|
||||
query.Lt("LENGTH(version)", 19) // 兼容以往版本
|
||||
query.Gt("version", version)
|
||||
} else {
|
||||
// 第一次访问时只取当前正在执行的或者执行失败的
|
||||
query.Where("(isDone=0 OR (isDone=1 AND isOk=0))")
|
||||
}
|
||||
_, err = query.
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
@@ -240,8 +252,16 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
|
||||
|
||||
// UpdateNodeTaskDone 修改节点任务的完成状态
|
||||
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(taskId).
|
||||
var query = this.Query(tx).
|
||||
Pk(taskId)
|
||||
if !isOk {
|
||||
version, err := this.increaseVersion(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query.Set("version", version)
|
||||
}
|
||||
_, err := query.
|
||||
Set("isDone", 1).
|
||||
Set("isOk", isOk).
|
||||
Set("error", errorMessage).
|
||||
@@ -373,3 +393,8 @@ func (this *NodeTaskDAO) UpdateTasksNotified(tx *dbs.Tx, taskIds []int64) error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 生成一个版本号
|
||||
func (this *NodeTaskDAO) increaseVersion(tx *dbs.Tx) (version int64, err error) {
|
||||
return SharedSysLockerDAO.Increase(tx, "NODE_TASK_VERSION", 0)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, NodeTaskTypeConfigChanged, 0)
|
||||
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
6
internal/db/models/ns_node_dao_test.go
Normal file
6
internal/db/models/ns_node_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -22,6 +22,7 @@ type NSNode struct {
|
||||
InactiveNotifiedAt uint64 `field:"inactiveNotifiedAt"` // 离线通知时间
|
||||
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
|
||||
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
|
||||
ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址
|
||||
}
|
||||
|
||||
type NSNodeOperator struct {
|
||||
@@ -43,6 +44,7 @@ type NSNodeOperator struct {
|
||||
InactiveNotifiedAt any // 离线通知时间
|
||||
ConnectedAPINodes any // 当前连接的API节点
|
||||
DdosProtection any // DDoS防护设置
|
||||
ApiNodeAddrs any // API节点地址
|
||||
}
|
||||
|
||||
func NewNSNodeOperator() *NSNodeOperator {
|
||||
|
||||
@@ -1,79 +1 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DecodeInstallStatus 安装状态
|
||||
func (this *NSNode) DecodeInstallStatus() (*NodeInstallStatus, error) {
|
||||
if len(this.InstallStatus) == 0 {
|
||||
return NewNodeInstallStatus(), nil
|
||||
}
|
||||
status := &NodeInstallStatus{}
|
||||
err := json.Unmarshal(this.InstallStatus, status)
|
||||
if err != nil {
|
||||
return NewNodeInstallStatus(), err
|
||||
}
|
||||
|
||||
// 如果N秒钟没有更新状态,则认为不在运行
|
||||
if status.IsRunning && status.UpdatedAt < time.Now().Unix()-10 {
|
||||
status.IsRunning = false
|
||||
status.IsFinished = true
|
||||
status.Error = "timeout"
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// DecodeStatus 节点状态
|
||||
func (this *NSNode) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
|
||||
if len(this.Status) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
err := json.Unmarshal(this.Status, status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// DecodeDDoSProtection 解析DDoS Protection设置
|
||||
func (this *NSNode) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
|
||||
if IsNull(this.DdosProtection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(this.DdosProtection, &result)
|
||||
if err != nil {
|
||||
// ignore err
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// HasDDoSProtection 检查是否有DDOS设置
|
||||
func (this *NSNode) HasDDoSProtection() bool {
|
||||
var config = this.DecodeDDoSProtection()
|
||||
if config != nil {
|
||||
return !config.IsPriorEmpty()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DecodeConnectedAPINodes 解析连接的API节点列表
|
||||
func (this *NSNode) DecodeConnectedAPINodes() []int64 {
|
||||
if IsNull(this.ConnectedAPINodes) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []int64{}
|
||||
err := json.Unmarshal(this.ConnectedAPINodes, &result)
|
||||
if err != nil {
|
||||
// ignore err
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -452,6 +453,75 @@ func (this *ServerBandwidthStatDAO) FindPercentileBetweenDays(tx *dbs.Tx, server
|
||||
return one.(*ServerBandwidthStat), nil
|
||||
}
|
||||
|
||||
// FindPercentileBetweenTimes 获取时间段内内百分位
|
||||
// timeFrom 开始时间,格式 YYYYMMDDHHII
|
||||
// timeTo 结束时间,格式 YYYYMMDDHHII
|
||||
func (this *ServerBandwidthStatDAO) FindPercentileBetweenTimes(tx *dbs.Tx, serverId int64, timeFrom string, timeTo string, percentile int32) (result *ServerBandwidthStat, err error) {
|
||||
var reg = regexp.MustCompile(`^\d{12}$`)
|
||||
if !reg.MatchString(timeFrom) {
|
||||
return nil, errors.New("invalid timeFrom '" + timeFrom + "'")
|
||||
}
|
||||
if !reg.MatchString(timeTo) {
|
||||
return nil, errors.New("invalid timeTo '" + timeTo + "'")
|
||||
}
|
||||
|
||||
if timeFrom > timeTo {
|
||||
timeFrom, timeTo = timeTo, timeFrom
|
||||
}
|
||||
|
||||
if percentile <= 0 {
|
||||
percentile = 95
|
||||
}
|
||||
|
||||
// 如果是100%以上,则快速返回
|
||||
if percentile >= 100 {
|
||||
one, err := this.Query(tx).
|
||||
Table(this.partialTable(serverId)).
|
||||
Attr("serverId", serverId).
|
||||
Between("CONCAT(day, timeAt)", timeFrom, timeTo).
|
||||
Desc("bytes").
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*ServerBandwidthStat), nil
|
||||
}
|
||||
|
||||
// 总数量
|
||||
total, err := this.Query(tx).
|
||||
Table(this.partialTable(serverId)).
|
||||
Attr("serverId", serverId).
|
||||
Between("CONCAT(day, timeAt)", timeFrom, timeTo).
|
||||
Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if total == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var offset int64
|
||||
|
||||
if total > 1 {
|
||||
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
|
||||
}
|
||||
|
||||
// 查询 nth 位置
|
||||
one, err := this.Query(tx).
|
||||
Table(this.partialTable(serverId)).
|
||||
Attr("serverId", serverId).
|
||||
Between("CONCAT(day, timeAt)", timeFrom, timeTo).
|
||||
Desc("bytes").
|
||||
Offset(offset).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*ServerBandwidthStat), nil
|
||||
}
|
||||
|
||||
// Clean 清理过期数据
|
||||
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
|
||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据
|
||||
|
||||
@@ -710,7 +710,10 @@ func (this *ServerDailyStatDAO) FindDistinctUserIds(tx *dbs.Tx, dayFrom string,
|
||||
return nil, err
|
||||
}
|
||||
for _, one := range ones {
|
||||
userIds = append(userIds, one.GetInt64("userId"))
|
||||
var userId = one.GetInt64("userId")
|
||||
if userId > 0 {
|
||||
userIds = append(userIds, userId)
|
||||
}
|
||||
}
|
||||
return userIds, nil
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, cacheMap *ut
|
||||
if cacheMap == nil {
|
||||
cacheMap = utils.NewCacheMap()
|
||||
}
|
||||
var cacheKey = this.Table + ":config:" + types.String(certId)
|
||||
var cacheKey = this.Table + ":ComposeCertConfig:" + types.String(certId)
|
||||
var cache, _ = cacheMap.Get(cacheKey)
|
||||
if cache != nil {
|
||||
return cache.(*sslconfigs.SSLCertConfig), nil
|
||||
@@ -600,6 +600,7 @@ func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 通知服务更新
|
||||
serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithSSLPolicyIds(tx, policyIds)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -613,5 +614,8 @@ func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 通知用户节点、API节点、管理系统(将来实现选择)更新
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -172,6 +172,24 @@ func (this *SysSettingDAO) ReadAdminUIConfig(tx *dbs.Tx, cacheMap *utils.CacheMa
|
||||
return &systemconfigs.AdminUIConfig{}, nil
|
||||
}
|
||||
|
||||
// ReadUserUIConfig 读取用户UI配置
|
||||
func (this *SysSettingDAO) ReadUserUIConfig(tx *dbs.Tx) (*systemconfigs.UserUIConfig, error) {
|
||||
valueJSON, err := this.ReadSetting(tx, systemconfigs.SettingCodeUserUIConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(valueJSON) == 0 {
|
||||
return systemconfigs.DefaultUserUIConfig(), nil
|
||||
}
|
||||
|
||||
var config = systemconfigs.DefaultUserUIConfig()
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更改
|
||||
func (this *SysSettingDAO) NotifyUpdate(tx *dbs.Tx, code string) error {
|
||||
switch code {
|
||||
|
||||
@@ -304,7 +304,10 @@ func (this *UserBandwidthStatDAO) FindDistinctUserIds(tx *dbs.Tx, dayFrom string
|
||||
|
||||
for _, one := range ones {
|
||||
locker.Lock()
|
||||
userIds = append(userIds, int64(one.(*UserBandwidthStat).UserId))
|
||||
var userId = int64(one.(*UserBandwidthStat).UserId)
|
||||
if userId > 0 {
|
||||
userIds = append(userIds, userId)
|
||||
}
|
||||
locker.Unlock()
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -72,7 +72,7 @@ func (this *DomainRecordsCache) WriteDomainRecords(providerId int64, domain stri
|
||||
}
|
||||
}
|
||||
|
||||
// QueryDomainRecord 从缓存中读取域名记录
|
||||
// QueryDomainRecord 从缓存中读取单条域名记录
|
||||
func (this *DomainRecordsCache) QueryDomainRecord(providerId int64, domain string, recordName string, recordType string) (record *dnstypes.Record, hasRecords bool, ok bool) {
|
||||
if providerId <= 0 || len(domain) == 0 {
|
||||
return
|
||||
@@ -117,6 +117,52 @@ func (this *DomainRecordsCache) QueryDomainRecord(providerId int64, domain strin
|
||||
return
|
||||
}
|
||||
|
||||
// QueryDomainRecords 从缓存中读取多条域名记录
|
||||
func (this *DomainRecordsCache) QueryDomainRecords(providerId int64, domain string, recordName string, recordType string) (records []*dnstypes.Record, hasRecords bool, ok bool) {
|
||||
if providerId <= 0 || len(domain) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
domain = types.String(providerId) + "@" + domain
|
||||
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
// check version
|
||||
var key = "DomainRecordsCache" + "@" + types.String(providerId) + "@" + domain
|
||||
version, err := models.SharedSysLockerDAO.Read(nil, key)
|
||||
if err != nil {
|
||||
remotelogs.Error("dnsclients.BaseProvider", "ReadDomainRecordsCache: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// find list
|
||||
list, recordsOk := this.domainRecordsMap[domain]
|
||||
if !recordsOk {
|
||||
return
|
||||
}
|
||||
if version != list.version {
|
||||
delete(this.domainRecordsMap, domain)
|
||||
return
|
||||
}
|
||||
|
||||
// check timestamp
|
||||
if list.updatedAt < time.Now().Unix()-86400 /** 缓存有效期为一天 **/ {
|
||||
delete(this.domainRecordsMap, domain)
|
||||
return
|
||||
}
|
||||
|
||||
hasRecords = true
|
||||
for _, r := range list.records {
|
||||
if r.Name == recordName && r.Type == recordType {
|
||||
records = append(records, r)
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteDomainRecord 删除域名记录缓存
|
||||
func (this *DomainRecordsCache) DeleteDomainRecord(providerId int64, domain string, recordId string) {
|
||||
if providerId <= 0 || len(domain) == 0 || len(recordId) == 0 {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type FindNSRecordsWithNameAndTypeResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSRecords []struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
TTL int32 `json:"ttl"`
|
||||
NSRoutes []struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"nsRoutes"`
|
||||
} `json:"nsRecords"`
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,30 @@ func (this *AliDNSProvider) QueryRecord(domain string, name string, recordType d
|
||||
return record, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *AliDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||
// 从缓存中读取
|
||||
if this.ProviderId > 0 {
|
||||
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
|
||||
if hasRecords { // 有效的搜索
|
||||
return records, nil
|
||||
}
|
||||
}
|
||||
|
||||
records, err := this.GetRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []*dnstypes.Record{}
|
||||
for _, record := range records {
|
||||
if record.Name == name && record.Type == recordType {
|
||||
result = append(result, record)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
|
||||
@@ -53,6 +53,20 @@ func TestAliDNSProvider_QueryRecord(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliDNSProvider_QueryRecords(t *testing.T) {
|
||||
provider, err := testAliDNSProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
{
|
||||
records, err := provider.QueryRecords("meloy.cn", "www", "A")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", records)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliDNSProvider_DeleteRecord(t *testing.T) {
|
||||
provider, err := testAliDNSProvider()
|
||||
if err != nil {
|
||||
|
||||
@@ -30,6 +30,9 @@ var cloudFlareHTTPClient = &http.Client{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
/**Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
return url.Parse("socks5://127.0.0.1:7890")
|
||||
},**/
|
||||
},
|
||||
}
|
||||
|
||||
@@ -64,14 +67,22 @@ func (this *CloudFlareProvider) Auth(params maps.Map) error {
|
||||
|
||||
// GetDomains 获取所有域名列表
|
||||
func (this *CloudFlareProvider) GetDomains() (domains []string, err error) {
|
||||
resp := new(cloudflare.ZonesResponse)
|
||||
err = this.doAPI(http.MethodGet, "zones", map[string]string{}, nil, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for page := 1; page <= 500; page++ {
|
||||
var resp = new(cloudflare.ZonesResponse)
|
||||
err = this.doAPI(http.MethodGet, "zones", map[string]string{
|
||||
"per_page": "50",
|
||||
"page": types.String(page),
|
||||
}, nil, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Result) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for _, zone := range resp.Result {
|
||||
domains = append(domains, zone.Name)
|
||||
for _, zone := range resp.Result {
|
||||
domains = append(domains, zone.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
@@ -134,7 +145,7 @@ func (this *CloudFlareProvider) QueryRecord(domain string, name string, recordTy
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := new(cloudflare.GetDNSRecordsResponse)
|
||||
var resp = new(cloudflare.GetDNSRecordsResponse)
|
||||
err = this.doAPI(http.MethodGet, "zones/"+zoneId+"/dns_records", map[string]string{
|
||||
"per_page": "100",
|
||||
"name": name + "." + domain,
|
||||
@@ -147,7 +158,7 @@ func (this *CloudFlareProvider) QueryRecord(domain string, name string, recordTy
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
record := resp.Result[0]
|
||||
var record = resp.Result[0]
|
||||
|
||||
// 修正Record
|
||||
if record.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(record.Content, ".") {
|
||||
@@ -166,6 +177,46 @@ func (this *CloudFlareProvider) QueryRecord(domain string, name string, recordTy
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *CloudFlareProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) (records []*dnstypes.Record, err error) {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp = new(cloudflare.GetDNSRecordsResponse)
|
||||
err = this.doAPI(http.MethodGet, "zones/"+zoneId+"/dns_records", map[string]string{
|
||||
"per_page": "100",
|
||||
"name": name + "." + domain,
|
||||
"type": recordType,
|
||||
}, nil, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Result) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, record := range resp.Result {
|
||||
// 修正Record
|
||||
if record.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(record.Content, ".") {
|
||||
record.Content += "."
|
||||
}
|
||||
|
||||
record.Name = strings.TrimSuffix(record.Name, "."+domain)
|
||||
|
||||
records = append(records, &dnstypes.Record{
|
||||
Id: record.Id,
|
||||
Name: record.Name,
|
||||
Type: record.Type,
|
||||
Value: record.Content,
|
||||
TTL: types.Int32(record.Ttl),
|
||||
Route: CloudFlareDefaultRoute,
|
||||
})
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
func (this *CloudFlareProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
|
||||
@@ -86,6 +86,21 @@ func TestCloudFlareProvider_QueryRecord(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFlareProvider_QueryRecords(t *testing.T) {
|
||||
provider, err := testCloudFlareProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
{
|
||||
t.Log("== www.meloy.cn/A ==")
|
||||
records, err := provider.QueryRecords("meloy.cn", "www", dnstypes.RecordTypeA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(records, t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFlareProvider_AddRecord(t *testing.T) {
|
||||
provider, err := testCloudFlareProvider()
|
||||
if err != nil {
|
||||
@@ -156,19 +171,19 @@ func testCloudFlareProvider() (ProviderInterface, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='cloudFlare' ORDER BY id DESC")
|
||||
one, err := db.FindOne("SELECT * FROM edgeDNSProviders WHERE type='cloudFlare' AND state=1 ORDER BY id DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if one == nil {
|
||||
return nil, errors.New("can not find providers with type 'cloudFlare'")
|
||||
}
|
||||
apiParams := maps.Map{}
|
||||
var apiParams = maps.Map{}
|
||||
err = json.Unmarshal([]byte(one.GetString("apiParams")), &apiParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
provider := &CloudFlareProvider{}
|
||||
var provider = &CloudFlareProvider{}
|
||||
err = provider.Auth(apiParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -103,7 +103,7 @@ func (this *CustomHTTPProvider) QueryRecord(domain string, name string, recordTy
|
||||
if len(resp) == 0 || string(resp) == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
record := &dnstypes.Record{}
|
||||
var record = &dnstypes.Record{}
|
||||
err = json.Unmarshal(resp, record)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -114,6 +114,28 @@ func (this *CustomHTTPProvider) QueryRecord(domain string, name string, recordTy
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *CustomHTTPProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) (result []*dnstypes.Record, err error) {
|
||||
resp, err := this.post(maps.Map{
|
||||
"action": "QueryRecords",
|
||||
"domain": domain,
|
||||
"name": name,
|
||||
"recordType": recordType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp) == 0 || string(resp) == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
result = []*dnstypes.Record{}
|
||||
err = json.Unmarshal(resp, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
func (this *CustomHTTPProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
_, err := this.post(maps.Map{
|
||||
|
||||
@@ -186,7 +186,30 @@ func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType d
|
||||
return record, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||
// 从缓存中读取
|
||||
if this.ProviderId > 0 {
|
||||
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
|
||||
if hasRecords { // 有效的搜索
|
||||
return records, nil
|
||||
}
|
||||
}
|
||||
|
||||
records, err := this.GetRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []*dnstypes.Record{}
|
||||
for _, record := range records {
|
||||
if record.Name == name && record.Type == recordType {
|
||||
result = append(result, record)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
|
||||
@@ -98,6 +98,21 @@ func TestDNSPodProvider_QueryRecord(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSPodProvider_QueryRecords(t *testing.T) {
|
||||
provider, _, err := testDNSPodProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
{
|
||||
records, err := provider.QueryRecords(DNSPodTestDomain, "hello-forward", dnstypes.RecordTypeCNAME)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(records, t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSPodProvider_UpdateRecord(t *testing.T) {
|
||||
provider, isInternational, err := testDNSPodProvider()
|
||||
if err != nil {
|
||||
|
||||
@@ -269,6 +269,54 @@ func (this *EdgeDNSAPIProvider) QueryRecord(domain string, name string, recordTy
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *EdgeDNSAPIProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||
var domainResp = &edgeapi.FindDomainWithNameResponse{}
|
||||
err := this.doAPI("/NSDomainService/FindNSDomainWithName", map[string]any{
|
||||
"name": domain,
|
||||
}, domainResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var domainId = domainResp.Data.NSDomain.Id
|
||||
if domainId == 0 {
|
||||
return nil, errors.New("can not find domain '" + domain + "'")
|
||||
}
|
||||
|
||||
var recordResp = &edgeapi.FindNSRecordsWithNameAndTypeResponse{}
|
||||
err = this.doAPI("/NSRecordService/FindNSRecordsWithNameAndType", map[string]any{
|
||||
"nsDomainId": domainId,
|
||||
"name": name,
|
||||
"type": recordType,
|
||||
}, recordResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result = []*dnstypes.Record{}
|
||||
for _, record := range recordResp.Data.NSRecords {
|
||||
if record.Id <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var routeCode = this.DefaultRoute()
|
||||
if len(record.NSRoutes) > 0 {
|
||||
routeCode = record.NSRoutes[0].Code
|
||||
}
|
||||
|
||||
result = append(result, &dnstypes.Record{
|
||||
Id: types.String(record.Id),
|
||||
Name: record.Name,
|
||||
Type: record.Type,
|
||||
Value: record.Value,
|
||||
Route: routeCode,
|
||||
TTL: record.TTL,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
func (this *EdgeDNSAPIProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
var domainResp = &edgeapi.FindDomainWithNameResponse{}
|
||||
|
||||
@@ -63,6 +63,18 @@ func TestEdgeDNSAPIProvider_QueryRecord(t *testing.T) {
|
||||
logs.PrintAsJSON(record)
|
||||
}
|
||||
|
||||
func TestEdgeDNSAPIProvider_QueryRecords(t *testing.T) {
|
||||
provider, err := testEdgeDNSAPIProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
record, err := provider.QueryRecords(edgeDNSAPIDomainName, "cdn", dnstypes.RecordTypeA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(record)
|
||||
}
|
||||
|
||||
func TestEdgeDNSAPIProvider_AddRecord(t *testing.T) {
|
||||
provider, err := testEdgeDNSAPIProvider()
|
||||
if err != nil {
|
||||
@@ -153,8 +165,8 @@ func testEdgeDNSAPIProvider() (dnsclients.ProviderInterface, error) {
|
||||
err := provider.Auth(maps.Map{
|
||||
"role": "user",
|
||||
"host": "http://127.0.0.1:8004",
|
||||
"accessKeyId": "JOvsyXIFqkQbh5kl",
|
||||
"accessKeySecret": "t0RY8YO3R58VbJJNp0RqKw9KWNpObwtE",
|
||||
"accessKeyId": "zr9cmR42AEZxRyIV",
|
||||
"accessKeySecret": "2w5p5NSZZuplUPsfPMzM7dFmTrI7xyja",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1328,6 +1328,41 @@ func (this *HuaweiDNSProvider) QueryRecord(domain string, name string, recordTyp
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
func (this *HuaweiDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||
var resp = new(huaweidns.RecordSetsResponse)
|
||||
err := this.doAPI(http.MethodGet, "/v2.1/recordsets", map[string]string{
|
||||
"name": name + "." + domain + ".",
|
||||
"type": recordType,
|
||||
}, maps.Map{}, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.RecordSets) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = []*dnstypes.Record{}
|
||||
for _, recordSet := range resp.RecordSets {
|
||||
if len(recordSet.Records) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, record := range recordSet.Records {
|
||||
result = append(result, &dnstypes.Record{
|
||||
Id: recordSet.Id + "@" + record,
|
||||
Name: name,
|
||||
Type: recordType,
|
||||
Value: record,
|
||||
Route: recordSet.Line,
|
||||
TTL: types.Int32(recordSet.Ttl),
|
||||
})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddRecord 设置记录
|
||||
func (this *HuaweiDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
|
||||
@@ -57,7 +57,19 @@ func TestHuaweiDNSProvider_QueryRecord(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(record)
|
||||
logs.PrintAsJSON(record, t)
|
||||
}
|
||||
|
||||
func TestHuaweiDNSProvider_QueryRecords(t *testing.T) {
|
||||
provider, err := testHuaweiDNSProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
records, err := provider.QueryRecords("yun4s.cn", "abc", dnstypes.RecordTypeA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(records, t)
|
||||
}
|
||||
|
||||
func TestHuaweiDNSProvider_AddRecord(t *testing.T) {
|
||||
@@ -71,7 +83,7 @@ func TestHuaweiDNSProvider_AddRecord(t *testing.T) {
|
||||
Type: "A",
|
||||
Value: "192.168.2.40",
|
||||
Route: "Beijing",
|
||||
TTL: 120,
|
||||
TTL: 120,
|
||||
}
|
||||
err = provider.AddRecord("yun4s.cn", record)
|
||||
if err != nil {
|
||||
|
||||
@@ -22,6 +22,9 @@ type ProviderInterface interface {
|
||||
// QueryRecord 查询单个记录
|
||||
QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error)
|
||||
|
||||
// QueryRecords 查询多个记录
|
||||
QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error)
|
||||
|
||||
// AddRecord 设置记录
|
||||
AddRecord(domain string, newRecord *dnstypes.Record) error
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@ package installers
|
||||
type Env struct {
|
||||
OS string
|
||||
Arch string
|
||||
HelperName string
|
||||
HelperPath string
|
||||
}
|
||||
|
||||
@@ -147,9 +147,19 @@ func (this *BaseInstaller) LookupLatestInstaller(filePrefix string) (string, err
|
||||
|
||||
// InstallHelper 上传安装助手
|
||||
func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.NodeRole) (env *Env, err error) {
|
||||
uname, _, err := this.client.Exec("/usr/bin/uname -a")
|
||||
var unameRetries = 3
|
||||
var uname string
|
||||
for i := 0; i < unameRetries; i++ {
|
||||
uname, _, err = this.client.Exec("/usr/bin/uname -a")
|
||||
if len(uname) == 0 {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return env, err
|
||||
return env, errors.New("unable to execute 'uname -a' on this system: " + err.Error())
|
||||
}
|
||||
|
||||
if len(uname) == 0 {
|
||||
@@ -181,22 +191,41 @@ func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.Node
|
||||
archName = "386"
|
||||
}
|
||||
|
||||
exeName := "edge-installer-helper-" + osName + "-" + archName
|
||||
var exeName = "edge-installer-helper-" + osName + "-" + archName
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleDNS:
|
||||
exeName = "edge-installer-dns-helper-" + osName + "-" + archName
|
||||
}
|
||||
exePath := Tea.Root + "/installers/" + exeName
|
||||
var exePath = Tea.Root + "/installers/" + exeName
|
||||
|
||||
err = this.client.Copy(exePath, targetDir+"/"+exeName, 0777)
|
||||
if err != nil {
|
||||
return env, errors.New("copy '" + exeName + "' to '" + targetDir + "' failed: " + err.Error())
|
||||
var realHelperPath = ""
|
||||
|
||||
var firstCopyErr error
|
||||
for _, path := range []string{
|
||||
targetDir + "/" + exeName,
|
||||
this.client.UserHome() + "/" + exeName,
|
||||
"/tmp/" + exeName,
|
||||
} {
|
||||
err = this.client.Copy(exePath, path, 0777)
|
||||
if err != nil {
|
||||
if firstCopyErr == nil {
|
||||
firstCopyErr = err
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
firstCopyErr = nil
|
||||
realHelperPath = path
|
||||
break
|
||||
}
|
||||
}
|
||||
if firstCopyErr != nil {
|
||||
return env, errors.New("copy '" + exeName + "' to '" + targetDir + "' failed: " + firstCopyErr.Error())
|
||||
}
|
||||
|
||||
env = &Env{
|
||||
OS: osName,
|
||||
Arch: archName,
|
||||
HelperName: exeName,
|
||||
HelperPath: realHelperPath,
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
||||
}
|
||||
|
||||
// 上传安装文件
|
||||
filePrefix := "edge-node-" + env.OS + "-" + env.Arch
|
||||
var filePrefix = "edge-node-" + env.OS + "-" + env.Arch
|
||||
zipFile, err := this.LookupLatestInstaller(filePrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,16 +53,34 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
||||
if len(zipFile) == 0 {
|
||||
return errors.New("can not find installer file for " + env.OS + "/" + env.Arch)
|
||||
}
|
||||
targetZip := dir + "/" + filepath.Base(zipFile)
|
||||
err = this.client.Copy(zipFile, targetZip, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
var targetZip = ""
|
||||
var firstCopyErr error
|
||||
var zipName = filepath.Base(zipFile)
|
||||
for _, candidateTargetZip := range []string{
|
||||
dir + "/" + zipName,
|
||||
this.client.UserHome() + "/" + zipName,
|
||||
"/tmp/" + zipName,
|
||||
} {
|
||||
err = this.client.Copy(zipFile, candidateTargetZip, 0777)
|
||||
if err != nil {
|
||||
if firstCopyErr == nil {
|
||||
firstCopyErr = err
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
firstCopyErr = nil
|
||||
targetZip = candidateTargetZip
|
||||
break
|
||||
}
|
||||
}
|
||||
if firstCopyErr != nil {
|
||||
return errors.New("upload node file failed: " + firstCopyErr.Error())
|
||||
}
|
||||
|
||||
// 测试运行环境
|
||||
// 升级的节点暂时不列入测试
|
||||
if !nodeParams.IsUpgrading {
|
||||
_, stderr, err := this.client.Exec(dir + "/" + env.HelperName + " -cmd=test")
|
||||
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=test")
|
||||
if err != nil {
|
||||
return errors.New("test failed: " + err.Error())
|
||||
}
|
||||
@@ -72,7 +90,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
||||
}
|
||||
|
||||
// 如果是升级则优雅停止先前的进程
|
||||
exePath := dir + "/edge-node/bin/edge-node"
|
||||
var exePath = dir + "/edge-node/bin/edge-node"
|
||||
if nodeParams.IsUpgrading {
|
||||
_, err = this.client.Stat(exePath)
|
||||
if err == nil {
|
||||
@@ -87,7 +105,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
||||
}
|
||||
|
||||
// 解压
|
||||
_, stderr, err := this.client.Exec(dir + "/" + env.HelperName + " -cmd=unzip -zip=\"" + targetZip + "\" -target=\"" + dir + "\"")
|
||||
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=unzip -zip=\"" + targetZip + "\" -target=\"" + dir + "\"")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -94,13 +94,15 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if login == nil {
|
||||
installStatus.ErrorCode = "EMPTY_LOGIN"
|
||||
return errors.New("can not find node login information")
|
||||
}
|
||||
loginParams, err := login.DecodeSSHParams()
|
||||
if err != nil {
|
||||
return err
|
||||
var loginParams = &models.NodeLoginSSHParams{}
|
||||
if login != nil {
|
||||
sshLoginParams, err := login.DecodeSSHParams()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sshLoginParams != nil {
|
||||
loginParams = sshLoginParams
|
||||
}
|
||||
}
|
||||
|
||||
if len(loginParams.Host) == 0 {
|
||||
|
||||
@@ -165,7 +165,14 @@ func (this *SSHClient) Mkdir(path string) error {
|
||||
}
|
||||
|
||||
func (this *SSHClient) MkdirAll(path string) error {
|
||||
return this.sftp.MkdirAll(path)
|
||||
err := this.sftp.MkdirAll(path)
|
||||
if err != nil && this.sudo {
|
||||
_, _, err2 := this.execSudo("mkdir -p "+path, this.sudoPassword)
|
||||
if err2 == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (this *SSHClient) Chmod(path string, mode os.FileMode) error {
|
||||
|
||||
@@ -12,6 +12,11 @@ import (
|
||||
|
||||
// 注册服务
|
||||
func (this *APINode) registerServices(server *grpc.Server) {
|
||||
{
|
||||
var instance = this.serviceInstance(&services.PingService{}).(*services.PingService)
|
||||
pb.RegisterPingServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.APITokenService{}).(*services.APITokenService)
|
||||
pb.RegisterAPITokenServiceServer(server, instance)
|
||||
@@ -402,6 +407,16 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
pb.RegisterServerRegionProviderMonthlyStatServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.FormalClientSystemService{}).(*services.FormalClientSystemService)
|
||||
pb.RegisterFormalClientSystemServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.FormalClientBrowserService{}).(*services.FormalClientBrowserService)
|
||||
pb.RegisterFormalClientBrowserServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService)
|
||||
pb.RegisterServerClientSystemMonthlyStatServiceServer(server, instance)
|
||||
|
||||
@@ -6,11 +6,13 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/cespare/xxhash"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
var logChan = make(chan *pb.NodeLog, 1024)
|
||||
var logChan = make(chan *pb.NodeLog, 64) // 队列数量不需要太长,因为日志通常仅仅为调试用
|
||||
var sharedDAO DAOInterface
|
||||
|
||||
func init() {
|
||||
@@ -106,13 +108,33 @@ func uploadLogs() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const hashSize = 10
|
||||
var hashList = []uint64{}
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case log := <-logChan:
|
||||
err := sharedDAO.CreateLog(nil, nodeconfigs.NodeRoleAPI, log.NodeId, log.ServerId, log.OriginId, log.Level, log.Tag, log.Description, log.CreatedAt, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
// 是否已存在
|
||||
var hash = xxhash.Sum64String(types.String(log.NodeId) + "_" + log.Description)
|
||||
var found = false
|
||||
for _, h := range hashList {
|
||||
if h == hash {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 加入
|
||||
if !found {
|
||||
hashList = append(hashList, hash)
|
||||
if len(hashList) > hashSize {
|
||||
hashList = hashList[1:]
|
||||
}
|
||||
err := sharedDAO.CreateLog(nil, nodeconfigs.NodeRoleAPI, log.NodeId, log.ServerId, log.OriginId, log.Level, log.Tag, log.Description, log.CreatedAt, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
break Loop
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/tasks"
|
||||
@@ -604,8 +602,8 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
||||
}
|
||||
|
||||
// 小时流量统计
|
||||
hourFrom := timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
hourTo := timeutil.Format("YmdH")
|
||||
var hourFrom = timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
var hourTo = timeutil.Format("YmdH")
|
||||
this.BeginTag(ctx, "SharedTrafficHourlyStatDAO.FindHourlyStats")
|
||||
hourlyTrafficStats, err := stats.SharedTrafficHourlyStatDAO.FindHourlyStats(tx, hourFrom, hourTo)
|
||||
this.EndTag(ctx, "SharedTrafficHourlyStatDAO.FindHourlyStats")
|
||||
@@ -624,12 +622,6 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
||||
})
|
||||
}
|
||||
|
||||
// 是否是商业版
|
||||
isPlus, err := authority.SharedAuthorityKeyDAO.IsPlus(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 边缘节点升级信息
|
||||
{
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
@@ -645,51 +637,6 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
||||
result.NodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// 监控节点升级信息
|
||||
if isPlus {
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
NewVersion: teaconst.MonitorNodeVersion,
|
||||
}
|
||||
this.BeginTag(ctx, "SharedMonitorNodeDAO.CountAllLowerVersionNodes")
|
||||
countNodes, err := models.SharedMonitorNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion)
|
||||
this.EndTag(ctx, "SharedMonitorNodeDAO.CountAllLowerVersionNodes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgradeInfo.CountNodes = countNodes
|
||||
result.MonitorNodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// 认证节点升级信息
|
||||
if isPlus {
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
NewVersion: teaconst.AuthorityNodeVersion,
|
||||
}
|
||||
this.BeginTag(ctx, "SharedAuthorityNodeDAO.CountAllLowerVersionNodes")
|
||||
countNodes, err := authority.SharedAuthorityNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion)
|
||||
this.EndTag(ctx, "SharedAuthorityNodeDAO.CountAllLowerVersionNodes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgradeInfo.CountNodes = countNodes
|
||||
result.AuthorityNodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// 用户节点升级信息
|
||||
if isPlus {
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
NewVersion: teaconst.UserNodeVersion,
|
||||
}
|
||||
this.BeginTag(ctx, "SharedUserNodeDAO.CountAllLowerVersionNodes")
|
||||
countNodes, err := models.SharedUserNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion)
|
||||
this.EndTag(ctx, "SharedUserNodeDAO.CountAllLowerVersionNodes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgradeInfo.CountNodes = countNodes
|
||||
result.UserNodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// API节点升级信息
|
||||
{
|
||||
var apiVersion = req.ApiVersion
|
||||
@@ -709,34 +656,10 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
||||
result.ApiNodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// DNS节点升级信息
|
||||
if isPlus {
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
NewVersion: teaconst.DNSNodeVersion,
|
||||
}
|
||||
this.BeginTag(ctx, "SharedNSNodeDAO.CountAllLowerVersionNodes")
|
||||
countNodes, err := models.SharedNSNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion)
|
||||
this.EndTag(ctx, "SharedNSNodeDAO.CountAllLowerVersionNodes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgradeInfo.CountNodes = countNodes
|
||||
result.NsNodeUpgradeInfo = upgradeInfo
|
||||
}
|
||||
|
||||
// Report节点升级信息
|
||||
if isPlus {
|
||||
upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{
|
||||
NewVersion: teaconst.ReportNodeVersion,
|
||||
}
|
||||
this.BeginTag(ctx, "SharedReportNodeDAO.CountAllLowerVersionNodes")
|
||||
countNodes, err := models.SharedReportNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion)
|
||||
this.EndTag(ctx, "SharedReportNodeDAO.CountAllLowerVersionNodes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgradeInfo.CountNodes = countNodes
|
||||
result.ReportNodeUpgradeInfo = upgradeInfo
|
||||
// 额外的检查节点版本
|
||||
err = this.composeAdminDashboardExt(tx, ctx, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
@@ -759,63 +682,6 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
||||
})
|
||||
}
|
||||
|
||||
// 节点排行
|
||||
if isPlus {
|
||||
this.BeginTag(ctx, "SharedNodeTrafficHourlyStatDAO.FindTopNodeStats")
|
||||
topNodeStats, err := stats.SharedNodeTrafficHourlyStatDAO.FindTopNodeStats(tx, "node", hourFrom, hourTo, 10)
|
||||
this.EndTag(ctx, "SharedNodeTrafficHourlyStatDAO.FindTopNodeStats")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, stat := range topNodeStats {
|
||||
nodeName, err := models.SharedNodeDAO.FindNodeName(tx, int64(stat.NodeId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodeName) == 0 {
|
||||
continue
|
||||
}
|
||||
result.TopNodeStats = append(result.TopNodeStats, &pb.ComposeAdminDashboardResponse_NodeStat{
|
||||
NodeId: int64(stat.NodeId),
|
||||
NodeName: nodeName,
|
||||
CountRequests: int64(stat.CountRequests),
|
||||
Bytes: int64(stat.Bytes),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 地区流量排行
|
||||
if isPlus {
|
||||
this.BeginTag(ctx, "SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes")
|
||||
totalCountryBytes, err := stats.SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes(tx, timeutil.Format("Ymd"))
|
||||
this.EndTag(ctx, "SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if totalCountryBytes > 0 {
|
||||
topCountryStats, err := stats.SharedServerRegionCountryDailyStatDAO.ListSumStats(tx, timeutil.Format("Ymd"), "bytes", 0, 100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, stat := range topCountryStats {
|
||||
countryName, err := regions.SharedRegionCountryDAO.FindRegionCountryName(tx, int64(stat.CountryId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.TopCountryStats = append(result.TopCountryStats, &pb.ComposeAdminDashboardResponse_CountryStat{
|
||||
CountryName: countryName,
|
||||
Bytes: int64(stat.Bytes),
|
||||
CountRequests: int64(stat.CountRequests),
|
||||
AttackBytes: int64(stat.AttackBytes),
|
||||
CountAttackRequests: int64(stat.CountAttackRequests),
|
||||
Percent: float32(stat.Bytes*100) / float32(totalCountryBytes),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 指标数据
|
||||
this.BeginTag(ctx, "findMetricDataCharts")
|
||||
var pbCharts []*pb.MetricDataChart
|
||||
|
||||
15
internal/rpc/services/service_admin_ext.go
Normal file
15
internal/rpc/services/service_admin_ext.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// ComposeAdminDashboard方法扩展
|
||||
func (this *AdminService) composeAdminDashboardExt(tx *dbs.Tx, ctx context.Context, result *pb.ComposeAdminDashboardResponse) error {
|
||||
return nil
|
||||
}
|
||||
@@ -351,7 +351,7 @@ func (this *DNSDomainService) ExistAvailableDomains(ctx context.Context, req *pb
|
||||
|
||||
// 转换域名信息
|
||||
func (this *DNSDomainService) convertDomainToPB(tx *dbs.Tx, domain *dns.DNSDomain) (*pb.DNSDomain, error) {
|
||||
domainId := int64(domain.Id)
|
||||
var domainId = int64(domain.Id)
|
||||
|
||||
defaultRoute, err := dnsutils.FindDefaultDomainRoute(tx, domain)
|
||||
if err != nil {
|
||||
@@ -383,7 +383,6 @@ func (this *DNSDomainService) convertDomainToPB(tx *dbs.Tx, domain *dns.DNSDomai
|
||||
countAllNodes1 := int64(0)
|
||||
countAllServers1 := int64(0)
|
||||
for _, cluster := range clusters {
|
||||
|
||||
_, nodeRecords, serverRecords, countAllNodes, countAllServers, nodesChanged2, serversChanged2, err := this.findClusterDNSChanges(cluster, records, domain.Name, defaultRoute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -471,6 +470,7 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
|
||||
|
||||
// 新增的节点域名
|
||||
var nodeKeys = []string{}
|
||||
var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
|
||||
for _, node := range nodes {
|
||||
ipAddresses, err := models.SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
|
||||
if err != nil {
|
||||
@@ -500,7 +500,7 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
|
||||
if net.ParseIP(ip) == nil {
|
||||
continue
|
||||
}
|
||||
key := ip + "_" + route
|
||||
var key = ip + "_" + route
|
||||
nodeKeys = append(nodeKeys, key)
|
||||
record, ok := nodeRecordMapping[key]
|
||||
if !ok {
|
||||
@@ -508,6 +508,14 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
|
||||
if utils.IsIPv6(ip) {
|
||||
recordType = dnstypes.RecordTypeAAAA
|
||||
}
|
||||
|
||||
// 避免添加重复的记录
|
||||
var fullKey = clusterDnsName + "_" + recordType + "_" + ip + "_" + route
|
||||
if addingNodeRecordKeysMap[fullKey] {
|
||||
continue
|
||||
}
|
||||
addingNodeRecordKeysMap[fullKey] = true
|
||||
|
||||
result = append(result, maps.Map{
|
||||
"action": "create",
|
||||
"record": &dnstypes.Record{
|
||||
|
||||
143
internal/rpc/services/service_formal_client_browser.go
Normal file
143
internal/rpc/services/service_formal_client_browser.go
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
// FormalClientBrowserService 浏览器信息库服务
|
||||
type FormalClientBrowserService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// CreateFormalClientBrowser 创建浏览器信息
|
||||
func (this *FormalClientBrowserService) CreateFormalClientBrowser(ctx context.Context, req *pb.CreateFormalClientBrowserRequest) (*pb.CreateFormalClientBrowserResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 检查dataId是否存在
|
||||
var tx = this.NullTx()
|
||||
browser, err := models.SharedFormalClientBrowserDAO.FindBrowserWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if browser != nil {
|
||||
return nil, errors.New("dataId '" + req.DataId + "' already exists")
|
||||
}
|
||||
|
||||
browserId, err := models.SharedFormalClientBrowserDAO.CreateBrowser(tx, req.Name, req.Codes, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CreateFormalClientBrowserResponse{
|
||||
FormalClientBrowserId: browserId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CountFormalClientBrowsers 计算浏览器信息数量
|
||||
func (this *FormalClientBrowserService) CountFormalClientBrowsers(ctx context.Context, req *pb.CountFormalClientBrowsersRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
count, err := models.SharedFormalClientBrowserDAO.CountBrowsers(tx, req.Keyword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListFormalClientBrowsers 列出单页浏览器信息
|
||||
func (this *FormalClientBrowserService) ListFormalClientBrowsers(ctx context.Context, req *pb.ListFormalClientBrowsersRequest) (*pb.ListFormalClientBrowsersResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
browsers, err := models.SharedFormalClientBrowserDAO.ListBrowsers(tx, req.Keyword, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pbBrowsers = []*pb.FormalClientBrowser{}
|
||||
for _, browser := range browsers {
|
||||
pbBrowsers = append(pbBrowsers, &pb.FormalClientBrowser{
|
||||
Id: int64(browser.Id),
|
||||
Name: browser.Name,
|
||||
Codes: browser.DecodeCodes(),
|
||||
DataId: browser.DataId,
|
||||
State: types.Int32(browser.State),
|
||||
})
|
||||
}
|
||||
return &pb.ListFormalClientBrowsersResponse{
|
||||
FormalClientBrowsers: pbBrowsers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFormalClientBrowser 修改浏览器信息
|
||||
func (this *FormalClientBrowserService) UpdateFormalClientBrowser(ctx context.Context, req *pb.UpdateFormalClientBrowserRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.DataId) == 0 {
|
||||
return nil, errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查dataId是否已经被使用
|
||||
oldBrowser, err := models.SharedFormalClientBrowserDAO.FindBrowserWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oldBrowser != nil && int64(oldBrowser.Id) != req.FormalClientBrowserId {
|
||||
return nil, errors.New("the dataId '" + req.DataId + "' already has been used")
|
||||
}
|
||||
|
||||
err = models.SharedFormalClientBrowserDAO.UpdateBrowser(tx, req.FormalClientBrowserId, req.Name, req.Codes, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindFormalClientBrowserWithDataId 通过dataId查询浏览器信息
|
||||
func (this *FormalClientBrowserService) FindFormalClientBrowserWithDataId(ctx context.Context, req *pb.FindFormalClientBrowserWithDataIdRequest) (*pb.FindFormalClientBrowserWithDataIdResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
browser, err := models.SharedFormalClientBrowserDAO.FindBrowserWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if browser == nil {
|
||||
return &pb.FindFormalClientBrowserWithDataIdResponse{
|
||||
FormalClientBrowser: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.FindFormalClientBrowserWithDataIdResponse{
|
||||
FormalClientBrowser: &pb.FormalClientBrowser{
|
||||
Id: int64(browser.Id),
|
||||
Name: browser.Name,
|
||||
Codes: browser.DecodeCodes(),
|
||||
DataId: browser.DataId,
|
||||
State: types.Int32(browser.State),
|
||||
}}, nil
|
||||
}
|
||||
143
internal/rpc/services/service_formal_client_system.go
Normal file
143
internal/rpc/services/service_formal_client_system.go
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
// FormalClientSystemService 操作系统信息库服务
|
||||
type FormalClientSystemService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// CreateFormalClientSystem 创建操作系统信息
|
||||
func (this *FormalClientSystemService) CreateFormalClientSystem(ctx context.Context, req *pb.CreateFormalClientSystemRequest) (*pb.CreateFormalClientSystemResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 检查dataId是否存在
|
||||
var tx = this.NullTx()
|
||||
system, err := models.SharedFormalClientSystemDAO.FindSystemWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if system != nil {
|
||||
return nil, errors.New("dataId '" + req.DataId + "' already exists")
|
||||
}
|
||||
|
||||
systemId, err := models.SharedFormalClientSystemDAO.CreateSystem(tx, req.Name, req.Codes, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CreateFormalClientSystemResponse{
|
||||
FormalClientSystemId: systemId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CountFormalClientSystems 计算操作系统信息数量
|
||||
func (this *FormalClientSystemService) CountFormalClientSystems(ctx context.Context, req *pb.CountFormalClientSystemsRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
count, err := models.SharedFormalClientSystemDAO.CountSystems(tx, req.Keyword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListFormalClientSystems 列出单页操作系统信息
|
||||
func (this *FormalClientSystemService) ListFormalClientSystems(ctx context.Context, req *pb.ListFormalClientSystemsRequest) (*pb.ListFormalClientSystemsResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
systems, err := models.SharedFormalClientSystemDAO.ListSystems(tx, req.Keyword, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pbSystems = []*pb.FormalClientSystem{}
|
||||
for _, system := range systems {
|
||||
pbSystems = append(pbSystems, &pb.FormalClientSystem{
|
||||
Id: int64(system.Id),
|
||||
Name: system.Name,
|
||||
Codes: system.DecodeCodes(),
|
||||
DataId: system.DataId,
|
||||
State: types.Int32(system.State),
|
||||
})
|
||||
}
|
||||
return &pb.ListFormalClientSystemsResponse{
|
||||
FormalClientSystems: pbSystems,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFormalClientSystem 修改操作系统信息
|
||||
func (this *FormalClientSystemService) UpdateFormalClientSystem(ctx context.Context, req *pb.UpdateFormalClientSystemRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.DataId) == 0 {
|
||||
return nil, errors.New("invalid dataId")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查dataId是否已经被使用
|
||||
oldSystem, err := models.SharedFormalClientSystemDAO.FindSystemWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oldSystem != nil && int64(oldSystem.Id) != req.FormalClientSystemId {
|
||||
return nil, errors.New("the dataId '" + req.DataId + "' already has been used")
|
||||
}
|
||||
|
||||
err = models.SharedFormalClientSystemDAO.UpdateSystem(tx, req.FormalClientSystemId, req.Name, req.Codes, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindFormalClientSystemWithDataId 通过dataId查询操作系统信息
|
||||
func (this *FormalClientSystemService) FindFormalClientSystemWithDataId(ctx context.Context, req *pb.FindFormalClientSystemWithDataIdRequest) (*pb.FindFormalClientSystemWithDataIdResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
system, err := models.SharedFormalClientSystemDAO.FindSystemWithDataId(tx, req.DataId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if system == nil {
|
||||
return &pb.FindFormalClientSystemWithDataIdResponse{
|
||||
FormalClientSystem: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.FindFormalClientSystemWithDataIdResponse{
|
||||
FormalClientSystem: &pb.FormalClientSystem{
|
||||
Id: int64(system.Id),
|
||||
Name: system.Name,
|
||||
Codes: system.DecodeCodes(),
|
||||
DataId: system.DataId,
|
||||
State: types.Int32(system.State),
|
||||
}}, nil
|
||||
}
|
||||
@@ -92,7 +92,9 @@ func init() {
|
||||
return nil
|
||||
}(key)
|
||||
if err != nil {
|
||||
remotelogs.Error("METRIC_STAT", "upload metric stats failed: "+err.Error())
|
||||
if !models.CheckSQLErrCode(err, 1213 /** transaction deadlock **/) {
|
||||
remotelogs.Error("METRIC_STAT", "upload metric stats failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 人为限速
|
||||
|
||||
@@ -546,7 +546,7 @@ func (this *NodeService) FindEnabledNode(ctx context.Context, req *pb.FindEnable
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
installStatusResult := &pb.NodeInstallStatus{}
|
||||
var installStatusResult = &pb.NodeInstallStatus{}
|
||||
if installStatus != nil {
|
||||
installStatusResult = &pb.NodeInstallStatus{
|
||||
IsRunning: installStatus.IsRunning,
|
||||
@@ -673,10 +673,12 @@ func (this *NodeService) FindEnabledNode(ctx context.Context, req *pb.FindEnable
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
CacheDiskDir: node.CacheDiskDir,
|
||||
CacheDiskSubDirsJSON: node.CacheDiskSubDirs,
|
||||
Level: int32(node.Level),
|
||||
LnAddrs: node.DecodeLnAddrs(),
|
||||
DnsRoutes: pbRoutes,
|
||||
EnableIPLists: node.EnableIPLists,
|
||||
ApiNodeAddrsJSON: node.ApiNodeAddrs,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
@@ -1708,7 +1710,16 @@ func (this *NodeService) UpdateNodeCache(ctx context.Context, req *pb.UpdateNode
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedNodeDAO.UpdateNodeCache(tx, req.NodeId, maxCacheDiskCapacityJSON, maxCacheMemoryCapacityJSON, req.CacheDiskDir)
|
||||
// cache sub dirs
|
||||
var cacheSubDirs = []*serverconfigs.CacheDir{}
|
||||
if len(req.CacheDiskSubDirsJSON) > 0 {
|
||||
err = json.Unmarshal(req.CacheDiskSubDirsJSON, &cacheSubDirs)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode 'cacheDiskSubDirsJSON' failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedNodeDAO.UpdateNodeCache(tx, req.NodeId, maxCacheDiskCapacityJSON, maxCacheMemoryCapacityJSON, req.CacheDiskDir, cacheSubDirs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2031,6 +2042,14 @@ func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.
|
||||
if dnsResolverConfig != nil {
|
||||
result.HasSystemSettings = dnsResolverConfig.Type != nodeconfigs.DNSResolverTypeDefault
|
||||
}
|
||||
|
||||
if !result.HasSystemSettings {
|
||||
// api node addresses
|
||||
var apiNodeAddrs = node.DecodeAPINodeAddrs()
|
||||
if len(apiNodeAddrs) > 0 {
|
||||
result.HasSystemSettings = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ddos protection
|
||||
@@ -2132,3 +2151,50 @@ func (this *NodeService) UpdateNodeRegionInfo(ctx context.Context, req *pb.Updat
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindNodeAPIConfig 查找单个节点的API相关配置
|
||||
func (this *NodeService) FindNodeAPIConfig(ctx context.Context, req *pb.FindNodeAPIConfigRequest) (*pb.FindNodeAPIConfigResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
node, err := models.SharedNodeDAO.FindNodeAPIConfig(tx, req.NodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node == nil {
|
||||
return &pb.FindNodeAPIConfigResponse{
|
||||
ApiNodeAddrsJSON: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.FindNodeAPIConfigResponse{
|
||||
ApiNodeAddrsJSON: node.ApiNodeAddrs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateNodeAPIConfig 修改某个节点的API相关配置
|
||||
func (this *NodeService) UpdateNodeAPIConfig(ctx context.Context, req *pb.UpdateNodeAPIConfigRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(req.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(req.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedNodeDAO.UpdateNodeAPIConfig(tx, req.NodeId, apiNodeAddrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
@@ -112,24 +112,24 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 标记为活跃状态
|
||||
// 是否发送恢复通知
|
||||
oldIsActive, err := models.SharedNodeDAO.FindNodeActive(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !oldIsActive {
|
||||
inactiveNotifiedAt, err := models.SharedNodeDAO.FindNodeInactiveNotifiedAt(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if inactiveNotifiedAt > 0 {
|
||||
// 设置为活跃
|
||||
err = models.SharedNodeDAO.UpdateNodeActive(tx, nodeId, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置为活跃
|
||||
err = models.SharedNodeDAO.UpdateNodeActive(tx, nodeId, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if inactiveNotifiedAt > 0 {
|
||||
// 发送恢复消息
|
||||
clusterId, err := models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||
if err != nil {
|
||||
@@ -145,12 +145,6 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 设置为活跃
|
||||
err = models.SharedNodeDAO.UpdateNodeActive(tx, nodeId, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,8 @@ func (this *NodeTaskService) FindNodeTasks(ctx context.Context, req *pb.FindNode
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = req
|
||||
|
||||
var tx = this.NullTx()
|
||||
tasks, err := models.SharedNodeTaskDAO.FindDoingNodeTasks(tx, nodeType, nodeId)
|
||||
tasks, err := models.SharedNodeTaskDAO.FindDoingNodeTasks(tx, nodeType, nodeId, req.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
23
internal/rpc/services/service_ping.go
Normal file
23
internal/rpc/services/service_ping.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// PingService Ping服务
|
||||
// 用来测试连接是否可用
|
||||
type PingService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// Ping 发起Ping
|
||||
func (this *PingService) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) {
|
||||
_, _, err := this.ValidateNodeId(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.PingResponse{}, nil
|
||||
}
|
||||
@@ -1709,17 +1709,20 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
|
||||
return nil
|
||||
}
|
||||
|
||||
systemId, err := models.SharedClientSystemDAO.FindSystemIdWithNameCacheable(tx, result.Name)
|
||||
systemId, err := models.SharedFormalClientSystemDAO.FindSystemIdWithNameCacheable(tx, result.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if systemId == 0 {
|
||||
systemId, err = models.SharedClientSystemDAO.CreateSystem(tx, result.Name)
|
||||
err = models.SharedClientSystemDAO.CreateSystemIfNotExists(tx, result.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 直接返回不再进行操作
|
||||
return nil
|
||||
}
|
||||
key := fmt.Sprintf("%d@%d@%s@%s", result.ServerId, systemId, result.Version, month)
|
||||
var key = fmt.Sprintf("%d@%d@%s@%s", result.ServerId, systemId, result.Version, month)
|
||||
serverStatLocker.Lock()
|
||||
serverHTTPSystemStatMap[key] += result.Count
|
||||
serverStatLocker.Unlock()
|
||||
@@ -1737,15 +1740,18 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
|
||||
return nil
|
||||
}
|
||||
|
||||
browserId, err := models.SharedClientBrowserDAO.FindBrowserIdWithNameCacheable(tx, result.Name)
|
||||
browserId, err := models.SharedFormalClientBrowserDAO.FindBrowserIdWithNameCacheable(tx, result.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if browserId == 0 {
|
||||
browserId, err = models.SharedClientBrowserDAO.CreateBrowser(tx, result.Name)
|
||||
err = models.SharedClientBrowserDAO.CreateBrowserIfNotExists(tx, result.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 直接返回不再进行操作
|
||||
return nil
|
||||
}
|
||||
key := fmt.Sprintf("%d@%d@%s@%s", result.ServerId, browserId, result.Version, month)
|
||||
serverStatLocker.Lock()
|
||||
|
||||
@@ -10,8 +10,10 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -186,14 +188,45 @@ func (this *ServerBandwidthStatService) FindHourlyServerBandwidthStats(ctx conte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Hours <= 0 {
|
||||
req.Hours = 12
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
stats, err := models.SharedServerBandwidthStatDAO.FindHourlyBandwidthStats(tx, req.ServerId, req.Hours)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// percentile
|
||||
var percentile = systemconfigs.DefaultBandwidthPercentile
|
||||
userUIConfig, _ := models.SharedSysSettingDAO.ReadUserUIConfig(tx)
|
||||
if userUIConfig != nil && userUIConfig.TrafficStats.BandwidthPercentile > 0 {
|
||||
percentile = userUIConfig.TrafficStats.BandwidthPercentile
|
||||
}
|
||||
|
||||
var timestamp = time.Now().Unix() - int64(req.Hours)*3600
|
||||
var timeFrom = timeutil.FormatTime("YmdH00", timestamp)
|
||||
var timeTo = timeutil.Format("YmdHi")
|
||||
|
||||
var pbNthStat *pb.FindHourlyServerBandwidthStatsResponse_Stat
|
||||
percentileStat, err := models.SharedServerBandwidthStatDAO.FindPercentileBetweenTimes(tx, req.ServerId, timeFrom, timeTo, percentile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if percentileStat != nil {
|
||||
pbNthStat = &pb.FindHourlyServerBandwidthStatsResponse_Stat{
|
||||
Day: percentileStat.Day,
|
||||
Hour: types.Int32(percentileStat.TimeAt[:2]),
|
||||
Bytes: int64(percentileStat.Bytes),
|
||||
Bits: int64(percentileStat.Bytes * 8),
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.FindHourlyServerBandwidthStatsResponse{
|
||||
Stats: stats,
|
||||
Stats: stats,
|
||||
Percentile: percentile,
|
||||
NthStat: pbNthStat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -205,13 +238,52 @@ func (this *ServerBandwidthStatService) FindDailyServerBandwidthStats(ctx contex
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
stats, err := models.SharedServerBandwidthStatDAO.FindDailyBandwidthStats(tx, req.ServerId, req.Days)
|
||||
|
||||
if req.Days <= 0 {
|
||||
req.Days = 30
|
||||
}
|
||||
|
||||
var timestamp = time.Now().Unix() - int64(req.Days)*86400
|
||||
var dayFrom = timeutil.FormatTime("Ymd", timestamp)
|
||||
var dayTo = timeutil.Format("Ymd")
|
||||
|
||||
stats, err := models.SharedServerBandwidthStatDAO.FindBandwidthStatsBetweenDays(tx, req.ServerId, dayFrom, dayTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pbStats = []*pb.FindDailyServerBandwidthStatsResponse_Stat{}
|
||||
for _, stat := range stats {
|
||||
pbStats = append(pbStats, &pb.FindDailyServerBandwidthStatsResponse_Stat{
|
||||
Day: stat.Day,
|
||||
Bytes: stat.Bytes,
|
||||
Bits: stat.Bytes * 8,
|
||||
})
|
||||
}
|
||||
|
||||
// percentile
|
||||
var percentile = systemconfigs.DefaultBandwidthPercentile
|
||||
userUIConfig, _ := models.SharedSysSettingDAO.ReadUserUIConfig(tx)
|
||||
if userUIConfig != nil && userUIConfig.TrafficStats.BandwidthPercentile > 0 {
|
||||
percentile = userUIConfig.TrafficStats.BandwidthPercentile
|
||||
}
|
||||
|
||||
var pbNthStat = &pb.FindDailyServerBandwidthStatsResponse_Stat{}
|
||||
percentileStat, err := models.SharedServerBandwidthStatDAO.FindPercentileBetweenDays(tx, req.ServerId, dayFrom, dayTo, percentile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if percentileStat != nil {
|
||||
pbNthStat = &pb.FindDailyServerBandwidthStatsResponse_Stat{
|
||||
Day: percentileStat.Day,
|
||||
Bytes: int64(percentileStat.Bytes),
|
||||
Bits: int64(percentileStat.Bytes * 8),
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.FindDailyServerBandwidthStatsResponse{
|
||||
Stats: stats,
|
||||
Stats: pbStats,
|
||||
Percentile: percentile,
|
||||
NthStat: pbNthStat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ func (this *ServerClientBrowserMonthlyStatService) FindTopServerClientBrowserMon
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pbStats := []*pb.FindTopServerClientBrowserMonthlyStatsResponse_Stat{}
|
||||
var pbStats = []*pb.FindTopServerClientBrowserMonthlyStatsResponse_Stat{}
|
||||
for _, stat := range statList {
|
||||
pbStat := &pb.FindTopServerClientBrowserMonthlyStatsResponse_Stat{
|
||||
Count: int64(stat.Count),
|
||||
Version: stat.Version,
|
||||
}
|
||||
browser, err := models.SharedClientBrowserDAO.FindEnabledClientBrowser(tx, int64(stat.BrowserId))
|
||||
browser, err := models.SharedFormalClientBrowserDAO.FindEnabledFormalClientBrowser(tx, int64(stat.BrowserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,6 @@ func (this *ServerClientBrowserMonthlyStatService) FindTopServerClientBrowserMon
|
||||
Id: int64(browser.Id),
|
||||
Name: browser.Name,
|
||||
}
|
||||
|
||||
pbStats = append(pbStats, pbStat)
|
||||
}
|
||||
return &pb.FindTopServerClientBrowserMonthlyStatsResponse{Stats: pbStats}, nil
|
||||
|
||||
@@ -31,13 +31,13 @@ func (this *ServerClientSystemMonthlyStatService) FindTopServerClientSystemMonth
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pbStats := []*pb.FindTopServerClientSystemMonthlyStatsResponse_Stat{}
|
||||
var pbStats = []*pb.FindTopServerClientSystemMonthlyStatsResponse_Stat{}
|
||||
for _, stat := range statList {
|
||||
pbStat := &pb.FindTopServerClientSystemMonthlyStatsResponse_Stat{
|
||||
Count: int64(stat.Count),
|
||||
Version: stat.Version,
|
||||
}
|
||||
system, err := models.SharedClientSystemDAO.FindEnabledClientSystem(tx, int64(stat.SystemId))
|
||||
system, err := models.SharedFormalClientSystemDAO.FindEnabledFormalClientSystem(tx, int64(stat.SystemId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
@@ -465,7 +466,16 @@ func (this *ServerStatBoardService) ComposeServerStatBoard(ctx context.Context,
|
||||
{
|
||||
var bandwidthMinutes = utils.RangeMinutes(time.Now(), 12, 5)
|
||||
var bandwidthStatMap = map[string]*pb.ServerBandwidthStat{}
|
||||
var timeFrom = ""
|
||||
var timeTo = ""
|
||||
for _, r := range utils.GroupMinuteRanges(bandwidthMinutes) {
|
||||
if len(timeFrom) == 0 || timeFrom > r.Day+r.MinuteFrom {
|
||||
timeFrom = r.Day + r.MinuteFrom
|
||||
}
|
||||
if len(timeTo) == 0 || timeTo < r.Day+r.MinuteTo {
|
||||
timeTo = r.Day + r.MinuteTo
|
||||
}
|
||||
|
||||
bandwidthStats, err := models.SharedServerBandwidthStatDAO.FindServerStats(tx, req.ServerId, r.Day, r.MinuteFrom, r.MinuteTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -499,6 +509,29 @@ func (this *ServerStatBoardService) ComposeServerStatBoard(ctx context.Context,
|
||||
}
|
||||
}
|
||||
result.MinutelyBandwidthStats = pbBandwidthStats
|
||||
|
||||
// percentile
|
||||
if len(timeFrom) > 0 && len(timeTo) > 0 {
|
||||
var percentile = systemconfigs.DefaultBandwidthPercentile
|
||||
userUIConfig, _ := models.SharedSysSettingDAO.ReadUserUIConfig(tx)
|
||||
if userUIConfig != nil && userUIConfig.TrafficStats.BandwidthPercentile > 0 {
|
||||
percentile = userUIConfig.TrafficStats.BandwidthPercentile
|
||||
}
|
||||
result.BandwidthPercentile = percentile
|
||||
|
||||
percentileStat, err := models.SharedServerBandwidthStatDAO.FindPercentileBetweenTimes(tx, req.ServerId, timeFrom, timeTo, percentile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if percentileStat != nil {
|
||||
result.MinutelyNthBandwidthStat = &pb.ServerBandwidthStat{
|
||||
Day: percentileStat.Day,
|
||||
TimeAt: percentileStat.TimeAt,
|
||||
Bytes: int64(percentileStat.Bytes),
|
||||
Bits: int64(percentileStat.Bytes * 8),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按日流量统计
|
||||
|
||||
@@ -483,8 +483,16 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
|
||||
var dailyTrafficStats = []*pb.ComposeUserDashboardResponse_DailyTrafficStat{}
|
||||
var dailyPeekBandwidthStats = []*pb.ComposeUserDashboardResponse_DailyPeekBandwidthStat{}
|
||||
|
||||
var dayFrom = ""
|
||||
var dayTo = ""
|
||||
for i := 30; i >= 0; i-- {
|
||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -i))
|
||||
if len(dayFrom) == 0 {
|
||||
dayFrom = day
|
||||
}
|
||||
if len(dayTo) == 0 || day > dayTo {
|
||||
dayTo = day
|
||||
}
|
||||
|
||||
// 流量
|
||||
trafficBytes, err := models.SharedServerDailyStatDAO.SumUserDaily(tx, req.UserId, 0, day)
|
||||
@@ -505,8 +513,7 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
|
||||
dailyTrafficStats = append(dailyTrafficStats, &pb.ComposeUserDashboardResponse_DailyTrafficStat{Day: day, Bytes: trafficBytes})
|
||||
dailyPeekBandwidthStats = append(dailyPeekBandwidthStats, &pb.ComposeUserDashboardResponse_DailyPeekBandwidthStat{Day: day, Bytes: peekBandwidthBytes})
|
||||
}
|
||||
|
||||
return &pb.ComposeUserDashboardResponse{
|
||||
var result = &pb.ComposeUserDashboardResponse{
|
||||
CountServers: countServers,
|
||||
MonthlyTrafficBytes: monthlyTrafficBytes,
|
||||
MonthlyPeekBandwidthBytes: monthlyPeekBandwidthBytes,
|
||||
@@ -514,7 +521,24 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
|
||||
DailyPeekBandwidthBytes: dailyPeekBandwidthBytes,
|
||||
DailyTrafficStats: dailyTrafficStats,
|
||||
DailyPeekBandwidthStats: dailyPeekBandwidthStats,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 带宽百分位
|
||||
var bandwidthPercentile = systemconfigs.DefaultBandwidthPercentile
|
||||
userConfig, _ := models.SharedSysSettingDAO.ReadUserUIConfig(tx)
|
||||
if userConfig != nil && userConfig.TrafficStats.BandwidthPercentile > 0 {
|
||||
bandwidthPercentile = userConfig.TrafficStats.BandwidthPercentile
|
||||
}
|
||||
result.BandwidthPercentile = bandwidthPercentile
|
||||
stat, err := models.SharedUserBandwidthStatDAO.FindPercentileBetweenDays(tx, req.UserId, 0, dayFrom, dayTo, bandwidthPercentile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
result.BandwidthPercentileBits = int64(stat.Bytes) * 8
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindUserNodeClusterId 获取用户所在的集群ID
|
||||
|
||||
@@ -22,6 +22,8 @@ type Setup struct {
|
||||
// 要返回的数据
|
||||
AdminNodeId string
|
||||
AdminNodeSecret string
|
||||
|
||||
logFp *os.File
|
||||
}
|
||||
|
||||
func NewSetup(config *Config) *Setup {
|
||||
@@ -31,15 +33,15 @@ func NewSetup(config *Config) *Setup {
|
||||
}
|
||||
|
||||
func NewSetupFromCmd() *Setup {
|
||||
args := cmd.ParseArgs(strings.Join(os.Args[1:], " "))
|
||||
var args = cmd.ParseArgs(strings.Join(os.Args[1:], " "))
|
||||
|
||||
config := &Config{}
|
||||
var config = &Config{}
|
||||
for _, arg := range args {
|
||||
index := strings.Index(arg, "=")
|
||||
var index = strings.Index(arg, "=")
|
||||
if index <= 0 {
|
||||
continue
|
||||
}
|
||||
value := arg[index+1:]
|
||||
var value = arg[index+1:]
|
||||
value = strings.Trim(value, "\"'")
|
||||
switch arg[:index] {
|
||||
case "-api-node-protocol":
|
||||
@@ -51,7 +53,18 @@ func NewSetupFromCmd() *Setup {
|
||||
}
|
||||
}
|
||||
|
||||
return NewSetup(config)
|
||||
var setup = NewSetup(config)
|
||||
|
||||
// log writer
|
||||
var tmpDir = os.TempDir()
|
||||
if len(tmpDir) > 0 {
|
||||
fp, err := os.OpenFile(tmpDir+"/edge-install.log", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err == nil {
|
||||
setup.logFp = fp
|
||||
}
|
||||
}
|
||||
|
||||
return setup
|
||||
}
|
||||
|
||||
func (this *Setup) Run() error {
|
||||
@@ -73,7 +86,7 @@ func (this *Setup) Run() error {
|
||||
}
|
||||
|
||||
// 执行SQL
|
||||
config := &dbs.Config{}
|
||||
var config = &dbs.Config{}
|
||||
configData, err := os.ReadFile(Tea.ConfigFile("db.yaml"))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -91,14 +104,22 @@ func (this *Setup) Run() error {
|
||||
return errors.New("can not find database config for env '" + Tea.Env + "'")
|
||||
}
|
||||
|
||||
executor := NewSQLExecutor(dbConfig)
|
||||
var executor = NewSQLExecutor(dbConfig)
|
||||
if this.logFp != nil {
|
||||
executor.SetLogWriter(this.logFp)
|
||||
|
||||
defer func() {
|
||||
_ = this.logFp.Close()
|
||||
_ = os.Remove(this.logFp.Name())
|
||||
}()
|
||||
}
|
||||
err = executor.Run(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Admin节点信息
|
||||
apiTokenDAO := models.NewApiTokenDAO()
|
||||
var apiTokenDAO = models.NewApiTokenDAO()
|
||||
token, err := apiTokenDAO.FindEnabledTokenWithRole(nil, "admin")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -110,7 +131,7 @@ func (this *Setup) Run() error {
|
||||
this.AdminNodeSecret = token.Secret
|
||||
|
||||
// 检查API节点
|
||||
dao := models.NewAPINodeDAO()
|
||||
var dao = models.NewAPINodeDAO()
|
||||
apiNodeId, err := dao.FindEnabledAPINodeIdWithAddr(nil, this.config.APINodeProtocol, this.config.APINodeHost, this.config.APINodePort)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -175,7 +196,7 @@ func (this *Setup) Run() error {
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
apiConfig := &configs.APIConfig{
|
||||
var apiConfig = &configs.APIConfig{
|
||||
NodeId: apiNode.UniqueId,
|
||||
Secret: apiNode.Secret,
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,7 +7,10 @@ import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@@ -38,6 +41,14 @@ var recordsTables = []*SQLRecordsTable{
|
||||
UniqueFields: []string{"name"},
|
||||
ExceptFields: []string{"customName", "customCodes"},
|
||||
},
|
||||
{
|
||||
TableName: "edgeFormalClientSystems",
|
||||
UniqueFields: []string{"dataId"},
|
||||
},
|
||||
{
|
||||
TableName: "edgeFormalClientBrowsers",
|
||||
UniqueFields: []string{"dataId"},
|
||||
},
|
||||
}
|
||||
|
||||
type sqlItem struct {
|
||||
@@ -46,21 +57,36 @@ type sqlItem struct {
|
||||
}
|
||||
|
||||
type SQLDump struct {
|
||||
logWriter io.Writer
|
||||
}
|
||||
|
||||
func NewSQLDump() *SQLDump {
|
||||
return &SQLDump{}
|
||||
}
|
||||
|
||||
func (this *SQLDump) SetLogWriter(logWriter io.Writer) {
|
||||
this.logWriter = logWriter
|
||||
}
|
||||
|
||||
// Dump 导出数据
|
||||
func (this *SQLDump) Dump(db *dbs.DB) (result *SQLDumpResult, err error) {
|
||||
func (this *SQLDump) Dump(db *dbs.DB, includingRecords bool) (result *SQLDumpResult, err error) {
|
||||
result = &SQLDumpResult{}
|
||||
|
||||
tableNames, err := db.TableNames()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, tableName := range tableNames {
|
||||
|
||||
fullTableMap, err := this.findFullTables(db, tableNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var autoIncrementReg = regexp.MustCompile(` AUTO_INCREMENT=\d+`)
|
||||
|
||||
for _, table := range fullTableMap {
|
||||
var tableName = table.Name
|
||||
|
||||
// 忽略一些分表
|
||||
if strings.HasPrefix(strings.ToLower(tableName), strings.ToLower("edgeHTTPAccessLogs_")) {
|
||||
continue
|
||||
@@ -69,15 +95,11 @@ func (this *SQLDump) Dump(db *dbs.DB) (result *SQLDumpResult, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
table, err := db.FindFullTable(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sqlTable := &SQLTable{
|
||||
var sqlTable = &SQLTable{
|
||||
Name: table.Name,
|
||||
Engine: table.Engine,
|
||||
Charset: table.Collation,
|
||||
Definition: regexp.MustCompile(` AUTO_INCREMENT=\d+`).ReplaceAllString(table.Code, ""),
|
||||
Definition: autoIncrementReg.ReplaceAllString(table.Code, ""),
|
||||
}
|
||||
|
||||
// 字段
|
||||
@@ -102,28 +124,30 @@ func (this *SQLDump) Dump(db *dbs.DB) (result *SQLDumpResult, err error) {
|
||||
|
||||
// Records
|
||||
var records = []*SQLRecord{}
|
||||
recordsTable := this.findRecordsTable(tableName)
|
||||
if recordsTable != nil {
|
||||
ones, _, err := db.FindOnes("SELECT * FROM " + tableName + " ORDER BY id ASC")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, one := range ones {
|
||||
record := &SQLRecord{
|
||||
Id: one.GetInt64("id"),
|
||||
Values: map[string]string{},
|
||||
UniqueFields: recordsTable.UniqueFields,
|
||||
ExceptFields: recordsTable.ExceptFields,
|
||||
if includingRecords {
|
||||
recordsTable := this.findRecordsTable(tableName)
|
||||
if recordsTable != nil {
|
||||
ones, _, err := db.FindOnes("SELECT * FROM " + tableName + " ORDER BY id ASC")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for k, v := range one {
|
||||
// 需要排除的字段
|
||||
if lists.ContainsString(record.ExceptFields, k) {
|
||||
continue
|
||||
for _, one := range ones {
|
||||
record := &SQLRecord{
|
||||
Id: one.GetInt64("id"),
|
||||
Values: map[string]string{},
|
||||
UniqueFields: recordsTable.UniqueFields,
|
||||
ExceptFields: recordsTable.ExceptFields,
|
||||
}
|
||||
for k, v := range one {
|
||||
// 需要排除的字段
|
||||
if lists.ContainsString(record.ExceptFields, k) {
|
||||
continue
|
||||
}
|
||||
|
||||
record.Values[k] = types.String(v)
|
||||
record.Values[k] = types.String(v)
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
}
|
||||
sqlTable.Records = records
|
||||
@@ -218,7 +242,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
}
|
||||
}
|
||||
|
||||
currentResult, err := this.Dump(db)
|
||||
currentResult, err := this.Dump(db, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -230,7 +254,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "+ table " + newTable.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
if len(newTable.Records) == 0 {
|
||||
execSQL(newTable.Definition)
|
||||
@@ -249,7 +273,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "+ " + newTable.Name + " " + newField.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + newTable.Name + " ADD `" + newField.Name + "` " + newField.Definition)
|
||||
if err != nil {
|
||||
@@ -259,7 +283,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "* " + newTable.Name + " " + newField.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + newTable.Name + " MODIFY `" + newField.Name + "` " + newField.Definition)
|
||||
if err != nil {
|
||||
@@ -276,7 +300,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "+ index " + newTable.Name + " " + newIndex.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + newTable.Name + " ADD " + newIndex.Definition)
|
||||
if err != nil {
|
||||
@@ -289,7 +313,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "* index " + newTable.Name + " " + newIndex.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + newTable.Name + " DROP KEY " + newIndex.Name)
|
||||
if err != nil {
|
||||
@@ -312,7 +336,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "- index " + oldTable.Name + " " + oldIndex.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + oldTable.Name + " DROP KEY " + oldIndex.Name)
|
||||
if err != nil {
|
||||
@@ -329,7 +353,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
var op = "- field " + oldTable.Name + " " + oldField.Name
|
||||
ops = append(ops, op)
|
||||
if showLog {
|
||||
fmt.Println(op)
|
||||
this.log(op)
|
||||
}
|
||||
_, err = db.Exec("ALTER TABLE " + oldTable.Name + " DROP COLUMN `" + oldField.Name + "`")
|
||||
if err != nil {
|
||||
@@ -343,7 +367,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
// +
|
||||
for _, record := range newTable.Records {
|
||||
var queryArgs = []string{}
|
||||
var queryValues = []interface{}{}
|
||||
var queryValues = []any{}
|
||||
var valueStrings = []string{}
|
||||
for _, field := range record.UniqueFields {
|
||||
queryArgs = append(queryArgs, field+"=?")
|
||||
@@ -367,7 +391,7 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
if one == nil {
|
||||
ops = append(ops, "+ record "+newTable.Name+" "+strings.Join(valueStrings, ", "))
|
||||
if showLog {
|
||||
fmt.Println("+ record " + newTable.Name + " " + strings.Join(valueStrings, ", "))
|
||||
this.log("+ record " + newTable.Name + " " + strings.Join(valueStrings, ", "))
|
||||
}
|
||||
var params = []string{}
|
||||
var args = []string{}
|
||||
@@ -388,10 +412,10 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
} else if !record.ValuesEquals(one) {
|
||||
ops = append(ops, "* record "+newTable.Name+" "+strings.Join(valueStrings, ", "))
|
||||
if showLog {
|
||||
fmt.Println("* record " + newTable.Name + " " + strings.Join(valueStrings, ", "))
|
||||
this.log("* record " + newTable.Name + " " + strings.Join(valueStrings, ", "))
|
||||
}
|
||||
args := []string{}
|
||||
values := []interface{}{}
|
||||
var args = []string{}
|
||||
var values = []any{}
|
||||
for k, v := range record.Values {
|
||||
if k == "id" {
|
||||
continue
|
||||
@@ -418,6 +442,65 @@ func (this *SQLDump) applyQueue(db *dbs.DB, newResult *SQLDumpResult, showLog bo
|
||||
return
|
||||
}
|
||||
|
||||
// 查找所有表的完整信息
|
||||
func (this *SQLDump) findFullTables(db *dbs.DB, tableNames []string) ([]*dbs.Table, error) {
|
||||
var fullTables = []*dbs.Table{}
|
||||
if len(tableNames) == 0 {
|
||||
return fullTables, nil
|
||||
}
|
||||
|
||||
var locker = &sync.Mutex{}
|
||||
var queue = make(chan string, len(tableNames))
|
||||
for _, tableName := range tableNames {
|
||||
queue <- tableName
|
||||
}
|
||||
|
||||
var wg = &sync.WaitGroup{}
|
||||
var concurrent = 8
|
||||
|
||||
if runtime.NumCPU() > 4 {
|
||||
concurrent = 32
|
||||
}
|
||||
|
||||
wg.Add(concurrent)
|
||||
var lastErr error
|
||||
for i := 0; i < concurrent; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case tableName := <-queue:
|
||||
table, err := db.FindFullTable(tableName)
|
||||
if err != nil {
|
||||
locker.Lock()
|
||||
lastErr = err
|
||||
locker.Unlock()
|
||||
return
|
||||
}
|
||||
locker.Lock()
|
||||
table.Name = tableName
|
||||
fullTables = append(fullTables, table)
|
||||
locker.Unlock()
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
// 排序
|
||||
sort.Slice(fullTables, func(i, j int) bool {
|
||||
return fullTables[i].Name < fullTables[j].Name
|
||||
})
|
||||
|
||||
return fullTables, nil
|
||||
}
|
||||
|
||||
// 查找有记录的表
|
||||
func (this *SQLDump) findRecordsTable(tableName string) *SQLRecordsTable {
|
||||
for _, table := range recordsTables {
|
||||
@@ -458,3 +541,12 @@ func (this *SQLDump) tryCreateIndex(err error, db *dbs.DB, tableName string, ind
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 打印操作日志
|
||||
func (this *SQLDump) log(message string) {
|
||||
if this.logWriter != nil {
|
||||
_, _ = this.logWriter.Write([]byte(message + "\n"))
|
||||
} else {
|
||||
fmt.Println(message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestSQLDump_Dump(t *testing.T) {
|
||||
}()
|
||||
|
||||
dump := NewSQLDump()
|
||||
result, err := dump.Dump(db)
|
||||
result, err := dump.Dump(db, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func TestSQLDump_Apply(t *testing.T) {
|
||||
}()
|
||||
|
||||
var dump = NewSQLDump()
|
||||
result, err := dump.Dump(db)
|
||||
result, err := dump.Dump(db, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@@ -22,7 +23,8 @@ var LatestSQLResult = &SQLDumpResult{}
|
||||
|
||||
// SQLExecutor 安装或升级SQL执行器
|
||||
type SQLExecutor struct {
|
||||
dbConfig *dbs.DBConfig
|
||||
dbConfig *dbs.DBConfig
|
||||
logWriter io.Writer
|
||||
}
|
||||
|
||||
func NewSQLExecutor(dbConfig *dbs.DBConfig) *SQLExecutor {
|
||||
@@ -33,7 +35,7 @@ func NewSQLExecutor(dbConfig *dbs.DBConfig) *SQLExecutor {
|
||||
|
||||
func NewSQLExecutorFromCmd() (*SQLExecutor, error) {
|
||||
// 执行SQL
|
||||
config := &dbs.Config{}
|
||||
var config = &dbs.Config{}
|
||||
configData, err := os.ReadFile(Tea.ConfigFile("db.yaml"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -45,6 +47,10 @@ func NewSQLExecutorFromCmd() (*SQLExecutor, error) {
|
||||
return NewSQLExecutor(config.DBs[Tea.Env]), nil
|
||||
}
|
||||
|
||||
func (this *SQLExecutor) SetLogWriter(logWriter io.Writer) {
|
||||
this.logWriter = logWriter
|
||||
}
|
||||
|
||||
func (this *SQLExecutor) Run(showLog bool) error {
|
||||
db, err := dbs.NewInstanceFromConfig(this.dbConfig)
|
||||
if err != nil {
|
||||
@@ -55,7 +61,11 @@ func (this *SQLExecutor) Run(showLog bool) error {
|
||||
_ = db.Close()
|
||||
}()
|
||||
|
||||
sqlDump := NewSQLDump()
|
||||
var sqlDump = NewSQLDump()
|
||||
sqlDump.SetLogWriter(this.logWriter)
|
||||
if this.logWriter != nil {
|
||||
showLog = true
|
||||
}
|
||||
_, err = sqlDump.Apply(db, LatestSQLResult, showLog)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -307,12 +317,12 @@ func (this *SQLExecutor) checkIPList(db *dbs.DB) error {
|
||||
}
|
||||
|
||||
// 创建名单
|
||||
_, err = db.Exec("INSERT INTO edgeIPLists(name, type, code, isPublic, createdAt) VALUES (?, ?, ?, ?, ?)", "公共黑名单", "black", "black", 1, time.Now().Unix())
|
||||
_, err = db.Exec("INSERT INTO edgeIPLists(name, type, code, isPublic, isGlobal, createdAt) VALUES (?, ?, ?, ?, ?, ?)", "公共黑名单", "black", "black", 1, 1, time.Now().Unix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO edgeIPLists(name, type, code, isPublic, createdAt) VALUES (?, ?, ?, ?, ?)", "公共白名单", "white", "white", 1, time.Now().Unix())
|
||||
_, err = db.Exec("INSERT INTO edgeIPLists(name, type, code, isPublic, isGlobal, createdAt) VALUES (?, ?, ?, ?, ?, ?)", "公共白名单", "white", "white", 1, 1, time.Now().Unix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -83,10 +83,13 @@ var upgradeFuncs = []*upgradeVersion{
|
||||
"0.4.11", upgradeV0_4_11,
|
||||
},
|
||||
{
|
||||
"v0.5.3", upgradeV0_5_3,
|
||||
"0.5.3", upgradeV0_5_3,
|
||||
},
|
||||
{
|
||||
"v0.5.6", upgradeV0_5_6,
|
||||
"0.5.6", upgradeV0_5_6,
|
||||
},
|
||||
{
|
||||
"0.5.8", upgradeV0_5_8,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
@@ -176,3 +177,39 @@ func upgradeV0_5_6(db *dbs.DB) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// v0.5.7
|
||||
func upgradeV0_5_8(db *dbs.DB) error {
|
||||
// node task versions
|
||||
{
|
||||
_, err := db.Exec("UPDATE edgeNodeTasks SET version=0 WHERE LENGTH(version)=19")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除操作系统和浏览器相关统计
|
||||
// 只删除当前月,避免因为数据过多阻塞
|
||||
{
|
||||
_, err := db.Exec("DELETE FROM edgeServerClientSystemMonthlyStats WHERE month=?", timeutil.Format("Ym"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
{
|
||||
_, err := db.Exec("DELETE FROM edgeServerClientBrowserMonthlyStats WHERE month=?", timeutil.Format("Ym"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 修复默认黑白名单不是全局的问题
|
||||
{
|
||||
_, err := db.Exec("UPDATE edgeIPLists SET isGlobal=1 WHERE id IN (1, 2)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -251,3 +251,4 @@ func TestUpgradeSQLData_v0_5_3(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ func (this *DNSTaskExecutor) loop() error {
|
||||
}
|
||||
}
|
||||
case dnsmodels.DNSTaskTypeNodeChange:
|
||||
err = this.doNode(taskId, int64(task.NodeId))
|
||||
err = this.doNode(taskId, int64(task.ClusterId), int64(task.NodeId))
|
||||
if err != nil {
|
||||
err = dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskError(nil, taskId, err.Error())
|
||||
if err != nil {
|
||||
@@ -269,8 +269,8 @@ func (this *DNSTaskExecutor) doServer(taskId int64, oldClusterId int64, serverId
|
||||
}
|
||||
|
||||
// 修改节点相关记录
|
||||
func (this *DNSTaskExecutor) doNode(taskId int64, nodeId int64) error {
|
||||
isOk := false
|
||||
func (this *DNSTaskExecutor) doNode(taskId int64, nodeClusterId int64, nodeId int64) error {
|
||||
var isOk = false
|
||||
defer func() {
|
||||
if isOk {
|
||||
err := dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskDone(nil, taskId)
|
||||
@@ -291,15 +291,22 @@ func (this *DNSTaskExecutor) doNode(taskId int64, nodeId int64) error {
|
||||
}
|
||||
|
||||
// 转交给cluster统一处理
|
||||
clusterIds, err := models.SharedNodeDAO.FindEnabledAndOnNodeClusterIds(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterChange)
|
||||
if nodeClusterId > 0 {
|
||||
err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, nodeClusterId, dnsmodels.DNSTaskTypeClusterChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
clusterIds, err := models.SharedNodeDAO.FindEnabledAndOnNodeClusterIds(tx, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOk = true
|
||||
@@ -361,6 +368,7 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, clusterId int64) error {
|
||||
return err
|
||||
}
|
||||
var isChanged = false
|
||||
var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
|
||||
for _, node := range nodes {
|
||||
routes, err := node.DNSRouteCodesForDomainId(domainId)
|
||||
if err != nil {
|
||||
@@ -398,6 +406,14 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, clusterId int64) error {
|
||||
if utils.IsIPv6(ip) {
|
||||
recordType = dnstypes.RecordTypeAAAA
|
||||
}
|
||||
|
||||
// 避免添加重复的记录
|
||||
var fullKey = clusterDNSName + "_" + recordType + "_" + ip + "_" + route
|
||||
if addingNodeRecordKeysMap[fullKey] {
|
||||
continue
|
||||
}
|
||||
addingNodeRecordKeysMap[fullKey] = true
|
||||
|
||||
err = manager.AddRecord(domain, &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: clusterDNSName,
|
||||
|
||||
@@ -64,11 +64,11 @@ func (this *HealthCheckClusterTask) Run() {
|
||||
if this.config.Interval == nil {
|
||||
return
|
||||
}
|
||||
duration := this.config.Interval.Duration()
|
||||
var duration = this.config.Interval.Duration()
|
||||
if duration <= 0 {
|
||||
return
|
||||
}
|
||||
ticker := utils.NewTicker(duration)
|
||||
var ticker = utils.NewTicker(duration)
|
||||
goman.New(func() {
|
||||
for ticker.Wait() {
|
||||
err := this.Loop()
|
||||
|
||||
@@ -38,8 +38,9 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cluster == nil {
|
||||
return nil, errors.New("can not find cluster with id '" + strconv.FormatInt(this.clusterId, 10) + "'")
|
||||
if cluster == nil || !cluster.IsOn {
|
||||
// 如果节点已经被删除,则不提示错误
|
||||
return nil, nil
|
||||
}
|
||||
if !cluster.HealthCheck.IsNotNull() {
|
||||
return nil, errors.New("health check config is not found")
|
||||
@@ -52,10 +53,16 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
|
||||
}
|
||||
|
||||
var results = []*HealthCheckResult{}
|
||||
|
||||
// 查询集群下的节点
|
||||
nodes, err := models.NewNodeDAO().FindAllEnabledNodesWithClusterId(nil, this.clusterId, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
if !node.IsOn {
|
||||
continue
|
||||
@@ -115,7 +122,7 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
|
||||
|
||||
var concurrent = 128
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
var wg = sync.WaitGroup{}
|
||||
wg.Add(countResults)
|
||||
for i := 0; i < concurrent; i++ {
|
||||
go func() {
|
||||
@@ -160,24 +167,27 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health
|
||||
}
|
||||
|
||||
if isChanged {
|
||||
// 发送消息
|
||||
var message = ""
|
||||
var messageType string
|
||||
var messageLevel string
|
||||
if result.IsOk {
|
||||
message = "健康检查成功,节点\"" + result.Node.Name + "\",IP\"" + result.NodeAddr + "\"已恢复上线"
|
||||
messageType = models.MessageTypeHealthCheckNodeUp
|
||||
messageLevel = models.MessageLevelSuccess
|
||||
} else {
|
||||
message = "健康检查失败,节点\"" + result.Node.Name + "\",IP\"" + result.NodeAddr + "\"已自动下线"
|
||||
messageType = models.MessageTypeHealthCheckNodeDown
|
||||
messageLevel = models.MessageLevelError
|
||||
}
|
||||
// 在线状态发生变化
|
||||
if healthCheckConfig.AutoDown {
|
||||
// 发送消息
|
||||
var message = ""
|
||||
var messageType string
|
||||
var messageLevel string
|
||||
if result.IsOk {
|
||||
message = "健康检查成功,节点\"" + result.Node.Name + "\",IP\"" + result.NodeAddr + "\"已恢复上线"
|
||||
messageType = models.MessageTypeHealthCheckNodeUp
|
||||
messageLevel = models.MessageLevelSuccess
|
||||
} else {
|
||||
message = "健康检查失败,节点\"" + result.Node.Name + "\",IP\"" + result.NodeAddr + "\"已自动下线"
|
||||
messageType = models.MessageTypeHealthCheckNodeDown
|
||||
messageLevel = models.MessageLevelError
|
||||
}
|
||||
|
||||
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), messageType, messageLevel, message, message, nil, false)
|
||||
if err != nil {
|
||||
this.logErr("HealthCheckExecutor", err.Error())
|
||||
return
|
||||
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), messageType, messageLevel, message, message, nil, false)
|
||||
if err != nil {
|
||||
this.logErr("HealthCheckExecutor", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 触发阈值
|
||||
@@ -188,8 +198,10 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health
|
||||
}
|
||||
}
|
||||
|
||||
// 我们只处理IP的上下线,不修改节点的状态
|
||||
return
|
||||
// 结束处理 ,因为我们只处理IP的上下线,不修改节点的状态
|
||||
if healthCheckConfig.AutoDown {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 修改节点状态
|
||||
@@ -206,6 +218,24 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health
|
||||
message := "健康检查失败,节点\"" + result.Node.Name + "\"已自动下线"
|
||||
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeDown, models.MessageLevelError, message, message, nil, false)
|
||||
}
|
||||
if err != nil {
|
||||
this.logErr("HealthCheckExecutor", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 通知健康检查结果
|
||||
var err error
|
||||
if result.IsOk {
|
||||
message := "节点\"" + result.Node.Name + "\"健康检查成功"
|
||||
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeUp, models.MessageLevelSuccess, message, message, nil, false)
|
||||
} else {
|
||||
message := "节点\"" + result.Node.Name + "\"健康检查失败"
|
||||
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeDown, models.MessageLevelError, message, message, nil, false)
|
||||
}
|
||||
if err != nil {
|
||||
this.logErr("HealthCheckExecutor", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +289,7 @@ func (this *HealthCheckExecutor) runNodeOnce(healthCheckConfig *serverconfigs.He
|
||||
MaxIdleConns: 1,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
MaxConnsPerHost: 1,
|
||||
IdleConnTimeout: 2 * time.Minute,
|
||||
IdleConnTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
TLSHandshakeTimeout: 0,
|
||||
TLSClientConfig: &tls.Config{
|
||||
|
||||
@@ -70,7 +70,16 @@ func (this *HealthCheckTask) Loop() error {
|
||||
|
||||
// 启动新的或更新老的
|
||||
for _, cluster := range clusters {
|
||||
clusterId := int64(cluster.Id)
|
||||
var clusterId = int64(cluster.Id)
|
||||
|
||||
// 检查当前集群上是否有服务,如果尚没有部署服务,则直接跳过
|
||||
countServers, err := models.SharedServerDAO.CountAllEnabledServersWithNodeClusterId(nil, clusterId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if countServers == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var config = &serverconfigs.HealthCheckConfig{}
|
||||
if len(cluster.HealthCheck) > 0 {
|
||||
|
||||
@@ -58,8 +58,8 @@ func (this *SSLCertExpireCheckExecutor) Loop() error {
|
||||
}
|
||||
for _, cert := range certs {
|
||||
// 发送消息
|
||||
subject := "SSL证书\"" + cert.Name + "\"在" + strconv.Itoa(days) + "天后将到期,"
|
||||
msg := "SSL证书\"" + cert.Name + "\"(" + string(cert.DnsNames) + ")在" + strconv.Itoa(days) + "天后将到期,"
|
||||
var subject = "SSL证书\"" + cert.Name + "\"在" + strconv.Itoa(days) + "天后将到期,"
|
||||
var msg = "SSL证书\"" + cert.Name + "\"(" + string(cert.DnsNames) + ")在" + strconv.Itoa(days) + "天后将到期,"
|
||||
|
||||
// 是否有自动更新任务
|
||||
if cert.AcmeTaskId > 0 {
|
||||
@@ -185,9 +185,9 @@ func (this *SSLCertExpireCheckExecutor) Loop() error {
|
||||
}
|
||||
for _, cert := range certs {
|
||||
// 发送消息
|
||||
today := timeutil.Format("Y-m-d")
|
||||
subject := "SSL证书\"" + cert.Name + "\"在今天(" + today + ")过期"
|
||||
msg := "SSL证书\"" + cert.Name + "\"(" + string(cert.DnsNames) + ")在今天(" + today + ")过期,请及时更新证书,之后将不再重复提醒。"
|
||||
var today = timeutil.Format("Y-m-d")
|
||||
var subject = "SSL证书\"" + cert.Name + "\"在今天(" + today + ")过期"
|
||||
var msg = "SSL证书\"" + cert.Name + "\"(" + string(cert.DnsNames) + ")在今天(" + today + ")过期,请及时更新证书,之后将不再重复提醒。"
|
||||
err = models.SharedMessageDAO.CreateMessage(nil, int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, subject, msg, maps.Map{
|
||||
"certId": cert.Id,
|
||||
"acmeTaskId": cert.AcmeTaskId,
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
pb "github.com/TeaOSLab/EdgeAPI/internal/tests/helloworld"
|
||||
pb2 "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
}
|
||||
|
||||
func (this *server) SayHello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if ok {
|
||||
jsonData, _ := json.MarshalIndent(md, "", " ")
|
||||
log.Print(string(jsonData))
|
||||
|
||||
_ = md
|
||||
}
|
||||
|
||||
return &pb.HelloReply{
|
||||
Message: "Hello, " + request.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestTCPServer(t *testing.T) {
|
||||
listener, err := net.Listen("tcp", ":8001")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer()
|
||||
pb.RegisterGreeterServer(s, &server{})
|
||||
pb2.RegisterNodeServiceServer(s, &services.NodeService{})
|
||||
|
||||
err = s.Serve(listener)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPClient(t *testing.T) {
|
||||
conn, err := grpc.Dial("127.0.0.1:8001", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
c := pb.NewGreeterClient(conn)
|
||||
|
||||
before := time.Now()
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "name", "liu", "age", "20")
|
||||
reply, err := c.SayHello(ctx, &pb.HelloRequest{
|
||||
Name: strings.Repeat("golang", 1),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(reply.Message)
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
|
||||
func TestTLSServer(t *testing.T) {
|
||||
listener, err := net.Listen("tcp", ":8001")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tlsCred, err := credentials.NewServerTLSFromFile("test.pem", "test.key")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer(grpc.Creds(tlsCred))
|
||||
pb.RegisterGreeterServer(s, &server{})
|
||||
err = s.Serve(listener)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSClient(t *testing.T) {
|
||||
tlsCred, err := credentials.NewClientTLSFromFile("test.pem", "www.hisock.cn")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial("127.0.0.1:8001", grpc.WithTransportCredentials(tlsCred))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
c := pb.NewGreeterClient(conn)
|
||||
|
||||
before := time.Now()
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "name", "liu")
|
||||
reply, err := c.SayHello(ctx, &pb.HelloRequest{
|
||||
Name: strings.Repeat("golang", 1),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(reply.Message)
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
|
||||
func BenchmarkClient(b *testing.B) {
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
tlsCred, err := credentials.NewClientTLSFromFile("test.pem", "www.hisock.cn")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
conn, err := grpc.Dial("127.0.0.1:8001", grpc.WithTransportCredentials(tlsCred))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
c := pb.NewGreeterClient(conn)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
ctx := context.Background()
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "name", "liu")
|
||||
reply, err := c.SayHello(ctx, &pb.HelloRequest{
|
||||
Name: "golang",
|
||||
})
|
||||
_, _ = reply, err
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "./helloworld";
|
||||
|
||||
service Greeter {
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {
|
||||
}
|
||||
}
|
||||
|
||||
message HelloRequest {
|
||||
string name = 100;
|
||||
int32 page_number = 101;
|
||||
repeated int32 ages = 102;
|
||||
}
|
||||
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message SearchResult {
|
||||
string query = 1;
|
||||
int32 page_number = 2;
|
||||
int32 result_per_page = 3;
|
||||
|
||||
enum Corpus {
|
||||
option allow_alias = true;
|
||||
|
||||
UNIVERSAL = 0;
|
||||
WEB = 1;
|
||||
IMAGES = 2;
|
||||
RUNNING = 2;
|
||||
}
|
||||
|
||||
Corpus corpus = 4;
|
||||
SearchResponse result = 5;
|
||||
map<string, SearchResponse> resultMap = 6;
|
||||
}
|
||||
|
||||
message SearchResponse {
|
||||
reserved 1 to 15;
|
||||
|
||||
int32 count = 16;
|
||||
bool isOk = 17;
|
||||
bytes padding = 18;
|
||||
}
|
||||
@@ -1,584 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: hello_service.proto
|
||||
|
||||
package helloworld
|
||||
|
||||
import (
|
||||
context "context"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type SearchResult_Corpus int32
|
||||
|
||||
const (
|
||||
SearchResult_UNIVERSAL SearchResult_Corpus = 0
|
||||
SearchResult_WEB SearchResult_Corpus = 1
|
||||
SearchResult_IMAGES SearchResult_Corpus = 2
|
||||
SearchResult_RUNNING SearchResult_Corpus = 2
|
||||
)
|
||||
|
||||
// Enum value maps for SearchResult_Corpus.
|
||||
var (
|
||||
SearchResult_Corpus_name = map[int32]string{
|
||||
0: "UNIVERSAL",
|
||||
1: "WEB",
|
||||
2: "IMAGES",
|
||||
// Duplicate value: 2: "RUNNING",
|
||||
}
|
||||
SearchResult_Corpus_value = map[string]int32{
|
||||
"UNIVERSAL": 0,
|
||||
"WEB": 1,
|
||||
"IMAGES": 2,
|
||||
"RUNNING": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x SearchResult_Corpus) Enum() *SearchResult_Corpus {
|
||||
p := new(SearchResult_Corpus)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x SearchResult_Corpus) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (SearchResult_Corpus) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_hello_service_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (SearchResult_Corpus) Type() protoreflect.EnumType {
|
||||
return &file_hello_service_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x SearchResult_Corpus) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SearchResult_Corpus.Descriptor instead.
|
||||
func (SearchResult_Corpus) EnumDescriptor() ([]byte, []int) {
|
||||
return file_hello_service_proto_rawDescGZIP(), []int{2, 0}
|
||||
}
|
||||
|
||||
type HelloRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,100,opt,name=name,proto3" json:"name,omitempty"`
|
||||
PageNumber int32 `protobuf:"varint,101,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"`
|
||||
Ages []int32 `protobuf:"varint,102,rep,packed,name=ages,proto3" json:"ages,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloRequest) Reset() {
|
||||
*x = HelloRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_hello_service_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hello_service_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hello_service_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetPageNumber() int32 {
|
||||
if x != nil {
|
||||
return x.PageNumber
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetAges() []int32 {
|
||||
if x != nil {
|
||||
return x.Ages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type HelloReply struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloReply) Reset() {
|
||||
*x = HelloReply{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_hello_service_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloReply) ProtoMessage() {}
|
||||
|
||||
func (x *HelloReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hello_service_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
|
||||
func (*HelloReply) Descriptor() ([]byte, []int) {
|
||||
return file_hello_service_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HelloReply) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`
|
||||
PageNumber int32 `protobuf:"varint,2,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"`
|
||||
ResultPerPage int32 `protobuf:"varint,3,opt,name=result_per_page,json=resultPerPage,proto3" json:"result_per_page,omitempty"`
|
||||
Corpus SearchResult_Corpus `protobuf:"varint,4,opt,name=corpus,proto3,enum=SearchResult_Corpus" json:"corpus,omitempty"`
|
||||
Result *SearchResponse `protobuf:"bytes,5,opt,name=result,proto3" json:"result,omitempty"`
|
||||
ResultMap map[string]*SearchResponse `protobuf:"bytes,6,rep,name=resultMap,proto3" json:"resultMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *SearchResult) Reset() {
|
||||
*x = SearchResult{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_hello_service_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SearchResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SearchResult) ProtoMessage() {}
|
||||
|
||||
func (x *SearchResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hello_service_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SearchResult.ProtoReflect.Descriptor instead.
|
||||
func (*SearchResult) Descriptor() ([]byte, []int) {
|
||||
return file_hello_service_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetQuery() string {
|
||||
if x != nil {
|
||||
return x.Query
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetPageNumber() int32 {
|
||||
if x != nil {
|
||||
return x.PageNumber
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetResultPerPage() int32 {
|
||||
if x != nil {
|
||||
return x.ResultPerPage
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetCorpus() SearchResult_Corpus {
|
||||
if x != nil {
|
||||
return x.Corpus
|
||||
}
|
||||
return SearchResult_UNIVERSAL
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetResult() *SearchResponse {
|
||||
if x != nil {
|
||||
return x.Result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SearchResult) GetResultMap() map[string]*SearchResponse {
|
||||
if x != nil {
|
||||
return x.ResultMap
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SearchResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Count int32 `protobuf:"varint,16,opt,name=count,proto3" json:"count,omitempty"`
|
||||
IsOk bool `protobuf:"varint,17,opt,name=isOk,proto3" json:"isOk,omitempty"`
|
||||
Padding []byte `protobuf:"bytes,18,opt,name=padding,proto3" json:"padding,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SearchResponse) Reset() {
|
||||
*x = SearchResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_hello_service_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SearchResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SearchResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SearchResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hello_service_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SearchResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SearchResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hello_service_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *SearchResponse) GetCount() int32 {
|
||||
if x != nil {
|
||||
return x.Count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SearchResponse) GetIsOk() bool {
|
||||
if x != nil {
|
||||
return x.IsOk
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SearchResponse) GetPadding() []byte {
|
||||
if x != nil {
|
||||
return x.Padding
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_hello_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_hello_service_proto_rawDesc = []byte{
|
||||
0x0a, 0x13, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x57, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x64, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x67,
|
||||
0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x65, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a,
|
||||
0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x67,
|
||||
0x65, 0x73, 0x18, 0x66, 0x20, 0x03, 0x28, 0x05, 0x52, 0x04, 0x61, 0x67, 0x65, 0x73, 0x22, 0x26,
|
||||
0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8e, 0x03, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63,
|
||||
0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1f, 0x0a,
|
||||
0x0b, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26,
|
||||
0x0a, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x67,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x50,
|
||||
0x65, 0x72, 0x50, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52,
|
||||
0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x43, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x52, 0x06, 0x63, 0x6f,
|
||||
0x72, 0x70, 0x75, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3a, 0x0a,
|
||||
0x09, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x4d, 0x61, 0x70, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x1c, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e,
|
||||
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09,
|
||||
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x4d, 0x61, 0x70, 0x1a, 0x4d, 0x0a, 0x0e, 0x52, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x53,
|
||||
0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3d, 0x0a, 0x06, 0x43, 0x6f, 0x72, 0x70,
|
||||
0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x10,
|
||||
0x00, 0x12, 0x07, 0x0a, 0x03, 0x57, 0x45, 0x42, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4d,
|
||||
0x41, 0x47, 0x45, 0x53, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e,
|
||||
0x47, 0x10, 0x02, 0x1a, 0x02, 0x10, 0x01, 0x22, 0x5a, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63,
|
||||
0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69,
|
||||
0x73, 0x4f, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x12,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x04, 0x08,
|
||||
0x01, 0x10, 0x10, 0x32, 0x33, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x28,
|
||||
0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x0d, 0x2e, 0x48, 0x65, 0x6c,
|
||||
0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x48, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x68, 0x65,
|
||||
0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_hello_service_proto_rawDescOnce sync.Once
|
||||
file_hello_service_proto_rawDescData = file_hello_service_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_hello_service_proto_rawDescGZIP() []byte {
|
||||
file_hello_service_proto_rawDescOnce.Do(func() {
|
||||
file_hello_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_hello_service_proto_rawDescData)
|
||||
})
|
||||
return file_hello_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_hello_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_hello_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_hello_service_proto_goTypes = []interface{}{
|
||||
(SearchResult_Corpus)(0), // 0: SearchResult.Corpus
|
||||
(*HelloRequest)(nil), // 1: HelloRequest
|
||||
(*HelloReply)(nil), // 2: HelloReply
|
||||
(*SearchResult)(nil), // 3: SearchResult
|
||||
(*SearchResponse)(nil), // 4: SearchResponse
|
||||
nil, // 5: SearchResult.ResultMapEntry
|
||||
}
|
||||
var file_hello_service_proto_depIdxs = []int32{
|
||||
0, // 0: SearchResult.corpus:type_name -> SearchResult.Corpus
|
||||
4, // 1: SearchResult.result:type_name -> SearchResponse
|
||||
5, // 2: SearchResult.resultMap:type_name -> SearchResult.ResultMapEntry
|
||||
4, // 3: SearchResult.ResultMapEntry.value:type_name -> SearchResponse
|
||||
1, // 4: Greeter.SayHello:input_type -> HelloRequest
|
||||
2, // 5: Greeter.SayHello:output_type -> HelloReply
|
||||
5, // [5:6] is the sub-list for method output_type
|
||||
4, // [4:5] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_hello_service_proto_init() }
|
||||
func file_hello_service_proto_init() {
|
||||
if File_hello_service_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_hello_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_hello_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloReply); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_hello_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SearchResult); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_hello_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SearchResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_hello_service_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_hello_service_proto_goTypes,
|
||||
DependencyIndexes: file_hello_service_proto_depIdxs,
|
||||
EnumInfos: file_hello_service_proto_enumTypes,
|
||||
MessageInfos: file_hello_service_proto_msgTypes,
|
||||
}.Build()
|
||||
File_hello_service_proto = out.File
|
||||
file_hello_service_proto_rawDesc = nil
|
||||
file_hello_service_proto_goTypes = nil
|
||||
file_hello_service_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConnInterface
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// GreeterClient is the client API for Greeter service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type GreeterClient interface {
|
||||
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
|
||||
}
|
||||
|
||||
type greeterClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
|
||||
return &greeterClient{cc}
|
||||
}
|
||||
|
||||
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
|
||||
out := new(HelloReply)
|
||||
err := c.cc.Invoke(ctx, "/Greeter/SayHello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GreeterServer is the server API for Greeter service.
|
||||
type GreeterServer interface {
|
||||
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
|
||||
}
|
||||
|
||||
// UnimplementedGreeterServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedGreeterServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
||||
}
|
||||
|
||||
func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
|
||||
s.RegisterService(&_Greeter_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GreeterServer).SayHello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Greeter/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Greeter_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Greeter",
|
||||
HandlerType: (*GreeterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SayHello",
|
||||
Handler: _Greeter_SayHello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "hello_service.proto",
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"math"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRandString(t *testing.T) {
|
||||
t.Log(rands.HexString(32))
|
||||
}
|
||||
|
||||
func TestCharset(t *testing.T) {
|
||||
t.Log(url.QueryEscape("中文"))
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
t.Log(math.MaxInt64)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user