智能DNS初步支持搜索引擎线路

This commit is contained in:
GoEdgeLab
2022-12-13 18:39:23 +08:00
parent 24a7ec8f02
commit 4213f03ded
18 changed files with 465 additions and 7 deletions

View File

@@ -0,0 +1,98 @@
package clients
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
type ClientAgentDAO dbs.DAO
func NewClientAgentDAO() *ClientAgentDAO {
return dbs.NewDAO(&ClientAgentDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeClientAgents",
Model: new(ClientAgent),
PkName: "id",
},
}).(*ClientAgentDAO)
}
var SharedClientAgentDAO *ClientAgentDAO
func init() {
dbs.OnReady(func() {
SharedClientAgentDAO = NewClientAgentDAO()
})
}
// FindClientAgentName 根据主键查找名称
func (this *ClientAgentDAO) FindClientAgentName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
Result("name").
FindStringCol("")
}
// FindAgent 查找Agent
func (this *ClientAgentDAO) FindAgent(tx *dbs.Tx, agentId int64) (*ClientAgent, error) {
if agentId <= 0 {
return nil, nil
}
one, err := this.Query(tx).
Pk(agentId).
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*ClientAgent), nil
}
// FindAgentIdWithCode 根据代号查找ID
func (this *ClientAgentDAO) FindAgentIdWithCode(tx *dbs.Tx, code string) (int64, error) {
return this.Query(tx).
ResultPk().
Attr("code", code).
FindInt64Col(0)
}
// FindAgentNameWithCode 根据代号查找Agent名称
func (this *ClientAgentDAO) FindAgentNameWithCode(tx *dbs.Tx, code string) (string, error) {
return this.Query(tx).
Result("name").
Attr("code", code).
FindStringCol("")
}
// UpdateAgentCountIPs 修改Agent拥有的IP数量
func (this *ClientAgentDAO) UpdateAgentCountIPs(tx *dbs.Tx, agentId int64, countIPs int64) error {
return this.Query(tx).
Pk(agentId).
Set("countIPs", countIPs).
UpdateQuickly()
}
// FindAllAgents 查找所有Agents
func (this *ClientAgentDAO) FindAllAgents(tx *dbs.Tx) (result []*ClientAgent, err error) {
_, err = this.Query(tx).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// FindAllNSAgents 查找所有DNS可以使用的Agents
func (this *ClientAgentDAO) FindAllNSAgents(tx *dbs.Tx) (result []*ClientAgent, err error) {
// 注意允许NS使用所有的Agent不管有没有IP数据
_, err = this.Query(tx).
Result("id", "name", "code").
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}

View File

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

View File

@@ -0,0 +1,105 @@
package clients
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
// TODO 需要定时对所有IP的PTR进行检查剔除已经变更的IP
type ClientAgentIPDAO dbs.DAO
func NewClientAgentIPDAO() *ClientAgentIPDAO {
return dbs.NewDAO(&ClientAgentIPDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeClientAgentIPs",
Model: new(ClientAgentIP),
PkName: "id",
},
}).(*ClientAgentIPDAO)
}
var SharedClientAgentIPDAO *ClientAgentIPDAO
func init() {
dbs.OnReady(func() {
SharedClientAgentIPDAO = NewClientAgentIPDAO()
})
}
// CreateIP 写入IP
func (this *ClientAgentIPDAO) CreateIP(tx *dbs.Tx, agentId int64, ip string, ptr string) error {
// 检查数据有效性
if agentId <= 0 || len(ip) == 0 {
return nil
}
// 限制ptr长度
if len(ptr) > 100 {
ptr = ptr[:100]
}
// 检查是否存在
exists, err := this.Query(tx).
Attr("agentId", agentId).
Attr("ip", ip).
Exist()
if err != nil {
return err
}
if exists {
return nil
}
var op = NewClientAgentIPOperator()
op.AgentId = agentId
op.IP = ip
op.Ptr = ptr
err = this.Save(tx, op)
if err != nil {
// 忽略duplicate错误
if models.CheckSQLDuplicateErr(err) {
return nil
}
return err
}
// 更新Agent IP数量
countIPs, err := this.CountAgentIPs(tx, agentId)
if err != nil {
return err
}
err = SharedClientAgentDAO.UpdateAgentCountIPs(tx, agentId, countIPs)
if err != nil {
return err
}
return nil
}
// ListIPsAfterId 列出某个ID之后的IP
func (this *ClientAgentIPDAO) ListIPsAfterId(tx *dbs.Tx, id int64, size int64) (result []*ClientAgentIP, err error) {
if id < 0 {
id = 0
}
_, err = this.Query(tx).
Result("id", "ip", "agentId").
Gt("id", id).
AscPk().
Limit(size). // 限制单次读取个数
Slice(&result).
FindAll()
return
}
// CountAgentIPs 计算Agent IP数量
func (this *ClientAgentIPDAO) CountAgentIPs(tx *dbs.Tx, agentId int64) (int64, error) {
return this.Query(tx).
Attr("agentId", agentId).
Count()
}

View File

@@ -0,0 +1,16 @@
package clients_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/clients"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"testing"
)
func TestClientAgentIPDAO_CreateIP(t *testing.T) {
var dao = clients.NewClientAgentIPDAO()
err := dao.CreateIP(nil, 1, "127.0.0.1", "")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,20 @@
package clients
// ClientAgentIP Agent IP
type ClientAgentIP struct {
Id uint64 `field:"id"` // ID
AgentId uint32 `field:"agentId"` // Agent ID
IP string `field:"ip"` // IP地址
Ptr string `field:"ptr"` // PTR值
}
type ClientAgentIPOperator struct {
Id any // ID
AgentId any // Agent ID
IP any // IP地址
Ptr any // PTR值
}
func NewClientAgentIPOperator() *ClientAgentIPOperator {
return &ClientAgentIPOperator{}
}

View File

@@ -0,0 +1 @@
package clients

View File

@@ -0,0 +1,24 @@
package clients
// ClientAgent Agent库
type ClientAgent struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
Code string `field:"code"` // 代号
Description string `field:"description"` // 介绍
Order uint32 `field:"order"` // 排序
CountIPs uint32 `field:"countIPs"` // IP数量
}
type ClientAgentOperator struct {
Id any // ID
Name any // 名称
Code any // 代号
Description any // 介绍
Order any // 排序
CountIPs any // IP数量
}
func NewClientAgentOperator() *ClientAgentOperator {
return &ClientAgentOperator{}
}

View File

@@ -0,0 +1,6 @@
package clients
// NSRouteCode NS线路代号
func (this *ClientAgent) NSRouteCode() string {
return "agent:" + this.Code
}

View File

@@ -1,13 +1,13 @@
package clients_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/clients"
_ "github.com/go-sql-driver/mysql"
"testing"
)
func TestClientBrowserDAO_CreateBrowser(t *testing.T) {
var dao = models.NewClientBrowserDAO()
var dao = clients.NewClientBrowserDAO()
err := dao.CreateBrowserIfNotExists(nil, "Hello")
if err != nil {
t.Fatal(err)
@@ -25,7 +25,7 @@ func TestClientBrowserDAO_CreateBrowser(t *testing.T) {
}
func TestClientBrowserDAO_Clean(t *testing.T) {
var dao = models.NewClientBrowserDAO()
var dao = clients.NewClientBrowserDAO()
err := dao.Clean(nil, 30)
if err != nil {
t.Fatal(err)

View File

@@ -1,13 +1,13 @@
package clients_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/clients"
_ "github.com/go-sql-driver/mysql"
"testing"
)
func TestClientSystemDAO_CreateSystemIfNotExists(t *testing.T) {
var dao = models.NewClientSystemDAO()
var dao = clients.NewClientSystemDAO()
{
err := dao.CreateSystemIfNotExists(nil, "Mac OS X")
if err != nil {
@@ -23,7 +23,7 @@ func TestClientSystemDAO_CreateSystemIfNotExists(t *testing.T) {
}
func TestClientSystemDAO_Clean(t *testing.T) {
var dao = models.NewClientSystemDAO()
var dao = clients.NewClientSystemDAO()
err := dao.Clean(nil, 30)
if err != nil {
t.Fatal(err)

View File

@@ -23,6 +23,7 @@ type NSCluster struct {
Answer dbs.JSON `field:"answer"` // 应答设置
SoaSerial uint64 `field:"soaSerial"` // SOA序列号
Email string `field:"email"` // 管理员邮箱
DetectAgents bool `field:"detectAgents"` // 是否监测Agents
}
type NSClusterOperator struct {
@@ -45,6 +46,7 @@ type NSClusterOperator struct {
Answer any // 应答设置
SoaSerial any // SOA序列号
Email any // 管理员邮箱
DetectAgents any // 是否监测Agents
}
func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -72,3 +72,11 @@ func CheckSQLErrCode(err error, code uint16) bool {
return false
}
// CheckSQLDuplicateErr 检查Duplicate错误
func CheckSQLDuplicateErr(err error) bool {
if err == nil {
return false
}
return CheckSQLErrCode(err, 1062)
}

View File

@@ -206,6 +206,23 @@ func (this *EdgeDNSAPIProvider) GetRoutes(domain string) (routes []*dnstypes.Rou
}
}
// Agent
{
var routesResp = &edgeapi.FindAllNSRoutesResponse{}
err = this.doAPI("/NSRouteService/FindAllAgentNSRoutes", map[string]any{}, routesResp)
if err != nil {
// 忽略错误因为老版本的EdgeDNS没有提供这个接口
err = nil
} else {
for _, route := range routesResp.Data.NSRoutes {
routes = append(routes, &dnstypes.Route{
Name: route.Name,
Code: route.Code,
})
}
}
}
// 自定义
{
var routesResp = &edgeapi.FindAllNSRoutesResponse{}

View File

@@ -414,6 +414,16 @@ func (this *APINode) registerServices(server *grpc.Server) {
pb.RegisterFormalClientBrowserServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&clients.ClientAgentIPService{}).(*clients.ClientAgentIPService)
pb.RegisterClientAgentIPServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&clients.ClientAgentService{}).(*clients.ClientAgentService)
pb.RegisterClientAgentServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.ServerClientSystemMonthlyStatService{}).(*services.ServerClientSystemMonthlyStatService)
pb.RegisterServerClientSystemMonthlyStatServiceServer(server, instance)

View File

@@ -0,0 +1,40 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package clients
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/clients"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// ClientAgentService Agent服务
type ClientAgentService struct {
services.BaseService
}
// FindAllClientAgents 查找所有Agent
func (this *ClientAgentService) FindAllClientAgents(ctx context.Context, req *pb.FindAllClientAgentsRequest) (*pb.FindAllClientAgentsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
agents, err := clients.SharedClientAgentDAO.FindAllAgents(tx)
if err != nil {
return nil, err
}
var pbAgents = []*pb.ClientAgent{}
for _, agent := range agents {
pbAgents = append(pbAgents, &pb.ClientAgent{
Id: int64(agent.Id),
Name: agent.Name,
Code: agent.Code,
Description: agent.Description,
CountIPs: int64(agent.CountIPs),
})
}
return &pb.FindAllClientAgentsResponse{ClientAgents: pbAgents}, nil
}

View File

@@ -0,0 +1,97 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package clients
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/clients"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// ClientAgentIPService Agent IP服务
type ClientAgentIPService struct {
services.BaseService
}
// CreateClientAgentIPs 创建一组IP
func (this *ClientAgentIPService) CreateClientAgentIPs(ctx context.Context, req *pb.CreateClientAgentIPsRequest) (*pb.RPCSuccess, error) {
// 先不支持网站服务节点,避免影响普通用户
_, err := this.ValidateNSNode(ctx)
if err != nil {
return nil, err
}
if len(req.AgentIPs) == 0 {
return this.Success()
}
var tx = this.NullTx()
for _, agentIP := range req.AgentIPs {
agentId, err := clients.SharedClientAgentDAO.FindAgentIdWithCode(tx, agentIP.AgentCode)
if err != nil {
return nil, err
}
if agentId <= 0 {
continue
}
err = clients.SharedClientAgentIPDAO.CreateIP(tx, agentId, agentIP.Ip, agentIP.Ptr)
if err != nil {
return nil, err
}
}
return this.Success()
}
// ListClientAgentIPsAfterId 查询最新的IP
func (this *ClientAgentIPService) ListClientAgentIPsAfterId(ctx context.Context, req *pb.ListClientAgentIPsAfterIdRequest) (*pb.ListClientAgentIPsAfterIdResponse, error) {
_, err := this.ValidateNSNode(ctx)
if err != nil {
return nil, err
}
if req.Size <= 0 {
req.Size = 10000
}
var tx = this.NullTx()
var agentMap = map[int64]*clients.ClientAgent{} // agentId => agentCode
agentIPs, err := clients.SharedClientAgentIPDAO.ListIPsAfterId(tx, req.Id, req.Size)
if err != nil {
return nil, err
}
var pbIPs = []*pb.ClientAgentIP{}
for _, agentIP := range agentIPs {
var agentId = int64(agentIP.AgentId)
agent, ok := agentMap[agentId]
if !ok {
agent, err = clients.SharedClientAgentDAO.FindAgent(tx, agentId)
if err != nil {
return nil, err
}
if agent == nil {
continue
}
agentMap[agentId] = agent
}
pbIPs = append(pbIPs, &pb.ClientAgentIP{
Id: int64(agentIP.Id),
Ip: agentIP.IP,
Ptr: "",
ClientAgent: &pb.ClientAgent{
Id: agentId,
Name: "",
Code: agent.Code,
Description: "",
},
})
}
return &pb.ListClientAgentIPsAfterIdResponse{
ClientAgentIPs: pbIPs,
}, nil
}

File diff suppressed because one or more lines are too long

View File

@@ -49,6 +49,14 @@ var recordsTables = []*SQLRecordsTable{
TableName: "edgeFormalClientBrowsers",
UniqueFields: []string{"dataId"},
},
{
TableName: "edgeClientAgents",
UniqueFields: []string{"code"},
},
{
TableName: "edgeClientAgentIPs",
UniqueFields: []string{"agentId", "ip"},
},
}
type sqlItem struct {