This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodes
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeDNS/internal/dbs"
"github.com/TeaOSLab/EdgeDNS/internal/models"
"github.com/TeaOSLab/EdgeDNS/internal/remotelogs"
"github.com/TeaOSLab/EdgeDNS/internal/rpc"
"github.com/iwind/TeaGo/types"
"strings"
"sync"
"time"
)
// DomainManager 域名管理器
type DomainManager struct {
domainMap map[int64]*models.NSDomain // domainId => domain
namesMap map[string]map[int64]*models.NSDomain // domain name => { domainId => domain }
clusterId int64
db *dbs.DB
version int64
locker *sync.RWMutex
notifier chan bool
}
// NewDomainManager 获取域名管理器对象
func NewDomainManager(db *dbs.DB, clusterId int64) *DomainManager {
return &DomainManager{
db: db,
domainMap: map[int64]*models.NSDomain{},
namesMap: map[string]map[int64]*models.NSDomain{},
clusterId: clusterId,
notifier: make(chan bool, 8),
locker: &sync.RWMutex{},
}
}
// Start 启动自动任务
func (this *DomainManager) Start() {
remotelogs.Println("DOMAIN_MANAGER", "starting ...")
// 从本地数据库中加载数据
err := this.Load()
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("DOMAIN_MANAGER", "load failed: "+err.Error())
} else {
remotelogs.Error("DOMAIN_MANAGER", "load failed: "+err.Error())
}
}
// 初始化运行
err = this.LoopAll()
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("DOMAIN_MANAGER", "loop failed: "+err.Error())
} else {
remotelogs.Error("DOMAIN_MANAGER", "loop failed: "+err.Error())
}
}
// 更新
var ticker = time.NewTicker(20 * time.Second)
for {
select {
case <-ticker.C:
case <-this.notifier:
}
err = this.LoopAll()
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("DOMAIN_MANAGER", "loop failed: "+err.Error())
} else {
remotelogs.Error("DOMAIN_MANAGER", "loop failed: "+err.Error())
}
}
}
}
func (this *DomainManager) LoopAll() error {
for {
hasNext, err := this.Loop()
if err != nil {
return err
}
if !hasNext {
break
}
}
return nil
}
// Load 从数据库中加载数据
func (this *DomainManager) Load() error {
var offset = 0
var size = 10000
for {
domains, err := this.db.ListDomains(this.clusterId, offset, size)
if err != nil {
return err
}
if len(domains) == 0 {
break
}
this.locker.Lock()
for _, domain := range domains {
this.domainMap[domain.Id] = domain
nameMap, ok := this.namesMap[domain.Name]
if ok {
nameMap[domain.Id] = domain
} else {
this.namesMap[domain.Name] = map[int64]*models.NSDomain{
domain.Id: domain,
}
}
if domain.Version > this.version {
this.version = domain.Version
}
}
this.locker.Unlock()
offset += size
}
if this.version > 0 {
this.version++
}
return nil
}
// Loop 单次循环任务
func (this *DomainManager) Loop() (hasNext bool, err error) {
client, err := rpc.SharedRPC()
if err != nil {
return false, err
}
resp, err := client.NSDomainRPC.ListNSDomainsAfterVersion(client.Context(), &pb.ListNSDomainsAfterVersionRequest{
Version: this.version,
Size: 20000,
})
if err != nil {
return false, err
}
var domains = resp.NsDomains
if len(domains) == 0 {
return false, nil
}
for _, domain := range domains {
this.processDomain(domain)
if domain.Version > this.version {
this.version = domain.Version
}
}
this.version++
return true, nil
}
// FindDomain 根据名称查找域名
func (this *DomainManager) FindDomain(name string) (domain *models.NSDomain, ok bool) {
this.locker.RLock()
defer this.locker.RUnlock()
nameMap, ok := this.namesMap[name]
if !ok {
return nil, false
}
for _, domain2 := range nameMap {
return domain2, true
}
return
}
// FindDomainWithId 根据域名ID查询域名
func (this *DomainManager) FindDomainWithId(domainId int64) (domain *models.NSDomain) {
this.locker.RLock()
defer this.locker.RUnlock()
return this.domainMap[domainId]
}
// NotifyUpdate 通知更新
func (this *DomainManager) NotifyUpdate() {
select {
case this.notifier <- true:
default:
}
}
// SplitDomain 分解域名
func (this *DomainManager) SplitDomain(fullDomainName string) (rootDomain *models.NSDomain, recordName string) {
if len(fullDomainName) == 0 {
return
}
fullDomainName = strings.TrimSuffix(fullDomainName, ".") // 去除尾部的点(.
fullDomainName = strings.ToLower(fullDomainName) // 转换为小写
var domainName = fullDomainName
var domain, ok = this.FindDomain(domainName)
if !ok {
for {
var index = strings.Index(domainName, ".")
if index < 0 {
break
}
domainName = domainName[index+1:]
domain, ok = this.FindDomain(domainName)
if ok {
recordName = fullDomainName[:len(fullDomainName)-len(domainName)-1]
break
}
}
}
return domain, recordName
}
// 处理域名
func (this *DomainManager) processDomain(domain *pb.NSDomain) {
if !domain.IsOn || domain.IsDeleted || domain.Status != dnsconfigs.NSDomainStatusVerified {
this.locker.Lock()
delete(this.domainMap, domain.Id)
nameMap, ok := this.namesMap[domain.Name]
if ok {
delete(nameMap, domain.Id)
if len(nameMap) == 0 {
delete(this.namesMap, domain.Name)
}
}
this.locker.Unlock()
// 从数据库中删除
if this.db != nil {
err := this.db.DeleteDomain(domain.Id)
if err != nil {
remotelogs.Error("DOMAIN_MANAGER", "delete domain from db failed: "+err.Error())
}
}
return
}
// 存入数据库
if this.db != nil {
exists, err := this.db.ExistsDomain(domain.Id)
if err != nil {
remotelogs.Error("DOMAIN_MANAGER", "query failed: "+err.Error())
} else {
if exists {
err = this.db.UpdateDomain(domain.Id, domain.NsCluster.Id, domain.UserId, domain.Name, domain.TsigJSON, domain.Version)
if err != nil {
remotelogs.Error("DOMAIN_MANAGER", "update failed: "+err.Error())
}
} else {
err = this.db.InsertDomain(domain.Id, domain.NsCluster.Id, domain.UserId, domain.Name, domain.TsigJSON, domain.Version)
if err != nil {
remotelogs.Error("DOMAIN_MANAGER", "insert failed: "+err.Error())
}
}
}
}
// 同集群的才需要加载
if this.clusterId == domain.NsCluster.Id {
this.locker.Lock()
var tsigConfig = &dnsconfigs.NSTSIGConfig{}
if len(domain.TsigJSON) > 0 {
err := json.Unmarshal(domain.TsigJSON, tsigConfig)
if err != nil {
remotelogs.Error("DOMAIN_MANAGER", "decode TSIG json failed: "+err.Error()+", domain: "+domain.Name+", domainId: "+types.String(domain.Id)+", JSON: "+string(domain.TsigJSON))
}
}
var nsDomain = &models.NSDomain{
Id: domain.Id,
ClusterId: domain.NsCluster.Id,
UserId: domain.UserId,
Name: domain.Name,
TSIG: tsigConfig,
Version: domain.Version,
}
this.domainMap[domain.Id] = nsDomain
nameMap, ok := this.namesMap[domain.Name]
if ok {
nameMap[nsDomain.Id] = nsDomain
} else {
this.namesMap[domain.Name] = map[int64]*models.NSDomain{
nsDomain.Id: nsDomain,
}
}
this.locker.Unlock()
} else {
// 不同集群的删除域名
this.locker.Lock()
delete(this.domainMap, domain.Id)
nameMap, ok := this.namesMap[domain.Name]
if ok {
delete(nameMap, domain.Id)
if len(nameMap) == 0 {
delete(this.namesMap, domain.Name)
}
}
this.locker.Unlock()
}
}