Files
waf-platform/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_node.go
2026-03-02 23:42:55 +08:00

289 lines
8.3 KiB
Go

package httpdns
import (
"context"
"encoding/json"
"errors"
"io"
"path/filepath"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/installers"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
stringutil "github.com/iwind/TeaGo/utils/string"
)
// HTTPDNSNodeService HTTPDNS节点服务
type HTTPDNSNodeService struct {
services.BaseService
pb.UnimplementedHTTPDNSNodeServiceServer
}
func (this *HTTPDNSNodeService) CreateHTTPDNSNode(ctx context.Context, req *pb.CreateHTTPDNSNodeRequest) (*pb.CreateHTTPDNSNodeResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
if req.ClusterId <= 0 {
return nil, errors.New("required 'clusterId'")
}
var nodeId int64
err = this.RunTx(func(tx *dbs.Tx) error {
nodeId, err = models.SharedHTTPDNSNodeDAO.CreateNode(tx, req.ClusterId, req.Name, req.InstallDir, req.IsOn)
if err != nil {
return err
}
return notifyHTTPDNSClusterTask(tx, req.ClusterId, models.HTTPDNSNodeTaskTypeConfigChanged)
})
if err != nil {
return nil, err
}
return &pb.CreateHTTPDNSNodeResponse{NodeId: nodeId}, nil
}
func (this *HTTPDNSNodeService) UpdateHTTPDNSNode(ctx context.Context, req *pb.UpdateHTTPDNSNodeRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
err = this.RunTx(func(tx *dbs.Tx) error {
node, err := models.SharedHTTPDNSNodeDAO.FindEnabledNode(tx, req.NodeId)
if err != nil {
return err
}
if node == nil {
return errors.New("node not found")
}
err = models.SharedHTTPDNSNodeDAO.UpdateNode(tx, req.NodeId, req.Name, req.InstallDir, req.IsOn)
if err != nil {
return err
}
return notifyHTTPDNSClusterTask(tx, int64(node.ClusterId), models.HTTPDNSNodeTaskTypeConfigChanged)
})
if err != nil {
return nil, err
}
return this.Success()
}
func (this *HTTPDNSNodeService) DeleteHTTPDNSNode(ctx context.Context, req *pb.DeleteHTTPDNSNodeRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
err = this.RunTx(func(tx *dbs.Tx) error {
node, err := models.SharedHTTPDNSNodeDAO.FindEnabledNode(tx, req.NodeId)
if err != nil {
return err
}
if node == nil {
return nil
}
err = models.SharedHTTPDNSNodeDAO.DisableNode(tx, req.NodeId)
if err != nil {
return err
}
return notifyHTTPDNSClusterTask(tx, int64(node.ClusterId), models.HTTPDNSNodeTaskTypeConfigChanged)
})
if err != nil {
return nil, err
}
return this.Success()
}
func (this *HTTPDNSNodeService) FindHTTPDNSNode(ctx context.Context, req *pb.FindHTTPDNSNodeRequest) (*pb.FindHTTPDNSNodeResponse, error) {
nodeId := req.NodeId
if nodeId <= 0 {
parsedNodeId, nodeErr := this.ValidateHTTPDNSNode(ctx)
if nodeErr != nil {
return nil, errors.New("invalid 'nodeId'")
}
nodeId = parsedNodeId
} else {
_, _, validateErr := this.ValidateAdminAndUser(ctx, true)
if validateErr != nil {
if _, nodeErr := this.ValidateHTTPDNSNode(ctx); nodeErr != nil {
return nil, validateErr
}
}
}
node, err := models.SharedHTTPDNSNodeDAO.FindEnabledNode(this.NullTx(), nodeId)
if err != nil {
return nil, err
}
pbNode := toPBNode(node)
// 认证信息
if pbNode != nil {
login, loginErr := models.SharedNodeLoginDAO.FindEnabledNodeLoginWithNodeId(this.NullTx(), nodeconfigs.NodeRoleHTTPDNS, nodeId)
if loginErr != nil {
return nil, loginErr
}
if login != nil {
pbNode.NodeLogin = &pb.NodeLogin{
Id: int64(login.Id),
Name: login.Name,
Type: login.Type,
Params: login.Params,
}
}
}
return &pb.FindHTTPDNSNodeResponse{Node: pbNode}, nil
}
func (this *HTTPDNSNodeService) ListHTTPDNSNodes(ctx context.Context, req *pb.ListHTTPDNSNodesRequest) (*pb.ListHTTPDNSNodesResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
nodes, err := models.SharedHTTPDNSNodeDAO.ListEnabledNodes(this.NullTx(), req.ClusterId)
if err != nil {
return nil, err
}
var pbNodes []*pb.HTTPDNSNode
for _, node := range nodes {
pbNodes = append(pbNodes, toPBNode(node))
}
return &pb.ListHTTPDNSNodesResponse{Nodes: pbNodes}, nil
}
func (this *HTTPDNSNodeService) UpdateHTTPDNSNodeStatus(ctx context.Context, req *pb.UpdateHTTPDNSNodeStatusRequest) (*pb.RPCSuccess, error) {
nodeId := req.GetNodeId()
isAdminCaller := false
if nodeId > 0 {
if _, adminErr := this.ValidateAdmin(ctx); adminErr == nil {
isAdminCaller = true
}
}
if !isAdminCaller {
if nodeId <= 0 {
parsedNodeId, err := this.ValidateHTTPDNSNode(ctx)
if err != nil {
return nil, err
}
nodeId = parsedNodeId
}
}
if nodeId <= 0 {
return nil, errors.New("invalid 'nodeId'")
}
err := models.SharedHTTPDNSNodeDAO.UpdateNodeStatus(this.NullTx(), nodeId, req.GetIsUp(), req.GetIsInstalled(), req.GetIsActive(), req.GetStatusJSON(), req.GetInstallStatusJSON())
if err != nil {
return nil, err
}
if isAdminCaller && shouldTriggerHTTPDNSInstall(req.GetInstallStatusJSON()) {
goman.New(func() {
installErr := installers.SharedHTTPDNSNodeQueue().InstallNodeProcess(nodeId, false)
if installErr != nil {
logs.Println("[RPC][HTTPDNS]install node failed:", installErr.Error())
}
})
}
return this.Success()
}
// UpdateHTTPDNSNodeLogin 修改HTTPDNS节点登录信息
func (this *HTTPDNSNodeService) UpdateHTTPDNSNodeLogin(ctx context.Context, req *pb.UpdateHTTPDNSNodeLoginRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if req.NodeLogin.Id <= 0 {
loginId, createErr := models.SharedNodeLoginDAO.CreateNodeLogin(tx, nodeconfigs.NodeRoleHTTPDNS, req.NodeId, req.NodeLogin.Name, req.NodeLogin.Type, req.NodeLogin.Params)
if createErr != nil {
return nil, createErr
}
req.NodeLogin.Id = loginId
}
err = models.SharedNodeLoginDAO.UpdateNodeLogin(tx, req.NodeLogin.Id, req.NodeLogin.Name, req.NodeLogin.Type, req.NodeLogin.Params)
if err != nil {
return nil, err
}
return this.Success()
}
// CheckHTTPDNSNodeLatestVersion 检查HTTPDNS节点新版本
func (this *HTTPDNSNodeService) CheckHTTPDNSNodeLatestVersion(ctx context.Context, req *pb.CheckHTTPDNSNodeLatestVersionRequest) (*pb.CheckHTTPDNSNodeLatestVersionResponse, error) {
_, _, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeHTTPDNS)
if err != nil {
return nil, err
}
deployFiles := installers.SharedDeployManager.LoadHTTPDNSNodeFiles()
for _, file := range deployFiles {
if file.OS == req.Os && file.Arch == req.Arch && stringutil.VersionCompare(file.Version, req.CurrentVersion) > 0 {
return &pb.CheckHTTPDNSNodeLatestVersionResponse{
HasNewVersion: true,
NewVersion: file.Version,
}, nil
}
}
return &pb.CheckHTTPDNSNodeLatestVersionResponse{HasNewVersion: false}, nil
}
// DownloadHTTPDNSNodeInstallationFile 下载最新HTTPDNS节点安装文件
func (this *HTTPDNSNodeService) DownloadHTTPDNSNodeInstallationFile(ctx context.Context, req *pb.DownloadHTTPDNSNodeInstallationFileRequest) (*pb.DownloadHTTPDNSNodeInstallationFileResponse, error) {
nodeId, err := this.ValidateHTTPDNSNode(ctx)
if err != nil {
return nil, err
}
var file = installers.SharedDeployManager.FindHTTPDNSNodeFile(req.Os, req.Arch)
if file == nil {
return &pb.DownloadHTTPDNSNodeInstallationFileResponse{}, nil
}
sum, err := file.Sum()
if err != nil {
return nil, err
}
data, offset, err := file.Read(req.ChunkOffset)
if err != nil && err != io.EOF {
return nil, err
}
// 增加下载速度监控
installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleHTTPDNS, nodeId, int64(len(data)))
return &pb.DownloadHTTPDNSNodeInstallationFileResponse{
Sum: sum,
Offset: offset,
ChunkData: data,
Version: file.Version,
Filename: filepath.Base(file.Path),
}, nil
}
func shouldTriggerHTTPDNSInstall(installStatusJSON []byte) bool {
if len(installStatusJSON) == 0 {
return false
}
installStatus := &models.NodeInstallStatus{}
err := json.Unmarshal(installStatusJSON, installStatus)
if err != nil {
return false
}
return installStatus.IsRunning && !installStatus.IsFinished
}