Compare commits

...

43 Commits

Author SHA1 Message Date
刘祥超
14315923d8 删除不必要的文件 2022-11-26 19:49:05 +08:00
刘祥超
3d3228fe96 修复删除节点时不能自动同步DNS的问题 2022-11-26 19:02:08 +08:00
刘祥超
173ac5a8aa 优化健康检查连接超时时间 2022-11-26 18:11:35 +08:00
刘祥超
e9c5d7e7cf 健康检查没有开启上下线的时候也发送节点状态变更通知 2022-11-26 15:54:16 +08:00
刘祥超
194127dce9 提交SQL 2022-11-26 15:39:16 +08:00
刘祥超
86cb7e9d41 缓存任务:校验缓存Key时支持域名中含有星号通配符 2022-11-26 15:03:24 +08:00
刘祥超
b2774de6a2 健康检查时只有开启了自动下线才发送上线通知 2022-11-25 15:48:57 +08:00
刘祥超
3a4722b701 用户可以使用管理员设置的公用线路 2022-11-24 17:19:51 +08:00
刘祥超
028aea4e3d 完全没有设置过SSH登录参数的节点也可以远程安装 2022-11-23 19:39:35 +08:00
刘祥超
c3dd97a7c1 增加数据库版本号 2022-11-22 14:32:04 +08:00
刘祥超
d527fcdd78 在节点详情中显示API节点地址 2022-11-21 21:09:06 +08:00
刘祥超
d6f311e057 节点可以单独设置所使用的API节点地址 2022-11-21 19:55:01 +08:00
刘祥超
991e08fa71 远程安装节点时uname读取失败时自动重试 2022-11-18 15:57:06 +08:00
刘祥超
06b44dc101 提升ssh sudo安装的稳定性 2022-11-18 15:44:53 +08:00
刘祥超
2d94b994fa DNS API支持查询多个同名记录/优化ACME申请 2022-11-17 17:33:59 +08:00
刘祥超
c036186dde 优化代码 2022-11-17 10:01:07 +08:00
刘祥超
bc2ad13037 集群被删除或者不可用时,健康检查时不提示错误 2022-11-16 14:10:03 +08:00
刘祥超
bfa04856aa 同步域名解析时自动剔除相同的节点A记录 2022-11-16 09:01:41 +08:00
刘祥超
feb1068441 边缘节点支持设置多个缓存目录 2022-11-15 20:35:59 +08:00
刘祥超
181a4d05b0 生成账单时只处理用户ID大于0的记录 2022-11-15 16:34:33 +08:00
刘祥超
c449265e05 cloudflare域名单页读取数从20修改为50,修复测试用例 2022-11-14 21:15:10 +08:00
刘祥超
e778616b5c 修复cloudflare域名只能读取第一页的问题 2022-11-14 21:04:13 +08:00
刘祥超
dad5be2670 缩短节点运行日志队列长度 2022-11-14 16:42:18 +08:00
刘祥超
414afd17b8 在写入API节点日志时尽量避免重复内容 2022-11-14 16:38:11 +08:00
刘祥超
86a806bca2 修复默认黑白名单不是全局的问题 2022-11-13 10:31:42 +08:00
刘祥超
faed7420a7 安装过程显示更详细内容 2022-11-11 21:48:00 +08:00
刘祥超
ae14ff4f9f 优化操作系统和浏览器统计相关程序 2022-11-11 17:48:30 +08:00
刘祥超
99e1658fdf 默认创建的IP名单设置为全局有效 2022-11-11 16:12:15 +08:00
刘祥超
e79264eefc 检查检查时先检查集群是否已经部署服务,如果没有部署服务,则直接跳过 2022-11-10 12:44:12 +08:00
刘祥超
dd0e26e7bc 访问日志搜索method:XXX和requestMethod:XXX方法 2022-11-09 11:58:50 +08:00
刘祥超
342c4bfbc2 NSRecords增加mxPriority字段 2022-11-06 20:34:57 +08:00
刘祥超
7d2b8fd4c8 保持导出SQL的稳定性 2022-11-06 19:26:23 +08:00
刘祥超
6426622992 优化代码 2022-11-06 19:13:47 +08:00
刘祥超
3d154411de 将指标统计导入到数据库时忽略 transaction deadlock错误 2022-11-06 16:03:33 +08:00
刘祥超
241f41e900 使用版本号来读取节点任务,提升任务同步稳定性 2022-11-06 12:03:11 +08:00
刘祥超
6c3d24d895 修复域名解析--DNS服务商--同步域名时无法解析集群额外附加的CNAME的问题 2022-11-05 19:25:35 +08:00
刘祥超
b2a0204f6b 优化代码 2022-11-05 14:39:40 +08:00
刘祥超
a9d71652b7 带宽相关数据增加百分位 2022-11-04 20:30:53 +08:00
刘祥超
1b6bfb33d6 用户看板增加带宽百分位 2022-11-04 17:39:53 +08:00
刘祥超
aec0d8d681 优化代码 2022-11-04 15:23:02 +08:00
刘祥超
e38871b52d 优化代码 2022-11-03 15:17:59 +08:00
刘祥超
c1b4551dd1 提升数据库升级速度 2022-11-02 16:58:09 +08:00
刘祥超
d479140f87 版本修改为0.5.8 2022-11-02 15:11:27 +08:00
103 changed files with 2659 additions and 1504 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 生成服务任务

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

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,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{}
}

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

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

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,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{}
}

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

View File

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

View 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("")
}

View File

@@ -0,0 +1,6 @@
package nameservers_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

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

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

View File

@@ -0,0 +1,6 @@
package nameservers_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View 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{}
}

View File

@@ -0,0 +1 @@
package nameservers

View 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("")
}

View File

@@ -0,0 +1,6 @@
package nameservers_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

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

View File

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

View File

@@ -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个月的数据

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 设置记录

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 设置记录

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,5 +3,5 @@ package installers
type Env struct {
OS string
Arch string
HelperName string
HelperPath string
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

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

View File

@@ -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())
}
}
// 人为限速

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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),
}
}
}
}
// 按日流量统计

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -251,3 +251,4 @@ func TestUpgradeSQLData_v0_5_3(t *testing.T) {
}
t.Log("ok")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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