refactor(dns/traffic_route): Reconstruct the DNS resolution service of Volcengine (#1472)

reconstruct the dns resolution service of volcengine.

Signed-off-by: LHSFK <lhsfk@141499.xyz>
This commit is contained in:
141499-LHSFK
2025-05-29 20:45:12 +08:00
committed by GitHub
parent 940727dea8
commit 3756c607c9

View File

@ -2,85 +2,70 @@ package dns
import (
"encoding/json"
"net/http"
"reflect"
"strconv"
"github.com/jeessy2/ddns-go/v6/config"
"github.com/jeessy2/ddns-go/v6/util"
)
const (
trafficRouteEndpoint = "https://open.volcengineapi.com"
trafficRouteVersion = "2018-08-01"
)
// TrafficRoute trafficRoute
// TrafficRoute 火山引擎DNS服务
type TrafficRoute struct {
DNS config.DNS
Domains config.Domains
TTL int
}
// TrafficRouteRecord record
// TrafficRouteMeta 解析记录
type TrafficRouteMeta struct {
ZID int `json:"ZID"`
RecordID string `json:"RecordID"` // 需要更新的解析记录ID
PQDN string `json:"PQDN"` // 解析记录所包含的主机名
Host string `json:"Host"` // 主机记录,即子域名的域名前缀
TTL int `json:"TTL"` // 解析记录的过期时间
Type string `json:"Type"` // 解析记录的类型
Line string `json:"Line"` // 解析记录对应的线路代号, 一般为default
Value string `json:"Value"` // 解析记录的记录值
ZID int `json:"ZID"` // 域名ID
RecordID string `json:"RecordID"` // 解析记录ID
Host string `json:"Host"` // 主机记录
Type string `json:"Type"` // 记录类型
Value string `json:"Value"` // 记录值
TTL int `json:"TTL"` // TTL值
Line string `json:"Line"` // 解析线路
}
// TrafficRouteZonesResp TrafficRoute zones返回结果
type TrafficRouteZonesResp struct {
Resp TrafficRouteRespMeta
Total int
// TrafficRouteResp API响应通用结构
type TrafficRouteResp struct {
ResponseMetadata struct {
RequestId string `json:"RequestId"`
Action string `json:"Action"`
Version string `json:"Version"`
Service string `json:"Service"`
Region string `json:"Region"`
Error struct {
Code string `json:"Code"`
Message string `json:"Message"`
} `json:"Error"`
} `json:"ResponseMetadata"`
Result struct {
// 域名列表相关字段
Zones []struct {
ZID int
ZoneName string
RecordCount int
}
Total int
}
ZID int `json:"ZID"`
ZoneName string `json:"ZoneName"`
RecordCount int `json:"RecordCount"`
} `json:"Zones,omitempty"`
Total int `json:"Total,omitempty"`
// 解析记录相关字段
Records []TrafficRouteMeta `json:"Records,omitempty"`
TotalCount int `json:"TotalCount,omitempty"`
// 创建/更新记录相关字段
RecordID string `json:"RecordID,omitempty"`
Status bool `json:"Status,omitempty"`
} `json:"Result"`
}
// TrafficRouteResp 修改/添加返回结果
type TrafficRouteRecordsResp struct {
Resp TrafficRouteRespMeta
Result struct {
TotalCount int
Records []TrafficRouteMeta
}
// TrafficRouteListZonesParams ListZones查询参数
type TrafficRouteListZonesParams struct {
Key string `json:"Key,omitempty"` // 获取包含特定关键字的域名(默认模糊搜索)
}
// TrafficRouteStatus TrafficRoute 返回状态
// https://www.volcengine.com/docs/6758/155089
type TrafficRouteStatus struct {
Resp TrafficRouteRespMeta
Result struct {
ZoneName string
Status bool
RecordCount int
}
}
// TrafficRoute 公共状态
type TrafficRouteRespMeta struct {
RequestId string
Action string
Version string
Service string
Region string
Error struct {
CodeN int
Code string
Message string
MessageCN string
}
// TrafficRouteListZonesResp
type TrafficRouteListZonesResp struct {
ZID int `json:"ZID"` // 域名ID
}
func (tr *TrafficRoute) Init(dnsConf *config.DnsConfig, ipv4cache *util.IpCache, ipv6cache *util.IpCache) {
@ -89,7 +74,6 @@ func (tr *TrafficRoute) Init(dnsConf *config.DnsConfig, ipv4cache *util.IpCache,
tr.DNS = dnsConf.DNS
tr.Domains.GetNewIp(dnsConf)
if dnsConf.TTL == "" {
// 默认 600s
tr.TTL = 600
} else {
ttl, err := strconv.Atoi(dnsConf.TTL)
@ -101,7 +85,7 @@ func (tr *TrafficRoute) Init(dnsConf *config.DnsConfig, ipv4cache *util.IpCache,
}
}
// AddUpdateDomainRecords 添加或更新 IPv4/IPv6 记录
// AddUpdateDomainRecords 添加或更新IPv4/IPv6记录
func (tr *TrafficRoute) AddUpdateDomainRecords() config.Domains {
tr.addUpdateDomainRecords("A")
tr.addUpdateDomainRecords("AAAA")
@ -110,87 +94,85 @@ func (tr *TrafficRoute) AddUpdateDomainRecords() config.Domains {
func (tr *TrafficRoute) addUpdateDomainRecords(recordType string) {
ipAddr, domains := tr.Domains.GetNewIpResult(recordType)
if ipAddr == "" {
return
}
for _, domain := range domains {
// 获取域名列表
ZoneResp, err := tr.listZones()
resp := TrafficRouteListZonesResp{}
tr.getZID(domain, &resp)
zoneID := resp.ZID
if err != nil {
util.Log("查询域名信息发生异常! %s", err)
domain.UpdateStatus = config.UpdatedFailed
return
}
if ZoneResp.Result.Total == 0 {
util.Log("在DNS服务商中未找到根域名: %s", domain.DomainName)
domain.UpdateStatus = config.UpdatedFailed
return
}
zoneID := ZoneResp.Result.Zones[0].ZID
var recordResp TrafficRouteRecordsResp
record := &TrafficRouteMeta{
ZID: zoneID,
}
err = tr.request(
var recordResp TrafficRouteResp
tr.request(
"GET",
"ListRecords",
record,
map[string][]string{"ZID": {strconv.Itoa(zoneID)}},
&recordResp,
)
if err != nil {
util.Log("查询域名信息发生异常! %s", err)
domain.UpdateStatus = config.UpdatedFailed
return
}
if recordResp.Result.Records == nil {
util.Log("查询域名信息发生异常! %s", recordResp.Resp.Error.Message)
domain.UpdateStatus = config.UpdatedFailed
return
}
find := false
found := false
for _, record := range recordResp.Result.Records {
if record.Type == recordType {
// 更新
tr.modify(record, zoneID, domain, recordType, ipAddr)
find = true
if record.Type == recordType && record.Host == domain.GetSubDomain() {
tr.modify(record, domain, ipAddr)
found = true
break
}
}
if !find {
// 新增
if !found {
tr.create(zoneID, domain, recordType, ipAddr)
}
}
}
// create 添加记录
// CreateRecord https://www.volcengine.com/docs/6758/155104
func (tr *TrafficRoute) create(zoneID int, domain *config.Domain, recordType string, ipAddr string) {
// getZID 获取域名的ZID
func (tr *TrafficRoute) getZID(domain *config.Domain, resp *TrafficRouteListZonesResp) {
var result TrafficRouteResp
err := tr.request(
"GET",
"ListZones",
map[string][]string{"Key": {domain.DomainName}},
&result,
)
if err != nil {
util.Log("查询域名信息发生异常! %s", err)
domain.UpdateStatus = config.UpdatedFailed
return
}
if len(result.Result.Zones) == 0 {
util.Log("在DNS服务商中未找到域名: %s", domain.DomainName)
domain.UpdateStatus = config.UpdatedFailed
return
}
for _, zone := range result.Result.Zones {
if zone.ZoneName == domain.DomainName {
resp.ZID = zone.ZID
return
}
}
}
// create 添加解析记录
func (tr *TrafficRoute) create(zoneID int, domain *config.Domain, recordType, ipAddr string) {
record := &TrafficRouteMeta{
ZID: zoneID,
Host: domain.GetSubDomain(),
Type: recordType,
Value: ipAddr,
TTL: tr.TTL,
Line: "default",
}
var status TrafficRouteStatus
var result TrafficRouteResp
err := tr.request(
"POST",
"CreateRecord",
record,
&status,
&result,
)
if err != nil {
@ -199,35 +181,32 @@ func (tr *TrafficRoute) create(zoneID int, domain *config.Domain, recordType str
return
}
if reflect.ValueOf(status.Result.Status).IsZero() {
if result.ResponseMetadata.Error.Code == "" {
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
util.Log("新增域名解析 %s 失败! 异常信息: %s, ", domain, status.Resp.Error.Message)
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, result.ResponseMetadata.Error.Message)
domain.UpdateStatus = config.UpdatedFailed
}
}
// update 修改记录
// UpdateRecord https://www.volcengine.com/docs/6758/155106
func (tr *TrafficRoute) modify(record TrafficRouteMeta, zoneID int, domain *config.Domain, recordType string, ipAddr string) {
// 相同不修改
if (record.Value == ipAddr) && (record.Host == domain.GetSubDomain()) {
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
// modify 修改解析记录
func (tr *TrafficRoute) modify(record TrafficRouteMeta, domain *config.Domain, ipAddr string) {
if record.Value == ipAddr {
util.Log("IP %s 没有变化,域名 %s", ipAddr, domain)
domain.UpdateStatus = config.UpdatedSuccess
return
}
var status TrafficRouteStatus
record.Host = domain.GetSubDomain()
record.Type = recordType
// record.Line = "default"
record.Value = ipAddr
record.TTL = tr.TTL
var result TrafficRouteResp
err := tr.request(
"POST",
"UpdateRecord",
record,
&status,
&result,
)
if err != nil {
@ -236,60 +215,67 @@ func (tr *TrafficRoute) modify(record TrafficRouteMeta, zoneID int, domain *conf
return
}
if reflect.ValueOf(status.Result.Status).IsZero() {
if result.ResponseMetadata.Error.Code == "" {
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
util.Log("更新域名解析 %s 失败! 异常信息: %s, ", domain, status.Resp.Error.Message)
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, result.ResponseMetadata.Error.Message)
domain.UpdateStatus = config.UpdatedFailed
}
}
// List 获得域名记录列表
// ListZones https://www.volcengine.com/docs/6758/155100
func (tr *TrafficRoute) listZones() (result TrafficRouteZonesResp, err error) {
record := TrafficRouteMeta{}
// parseRequestParams 解析请求参数
func (tr *TrafficRoute) parseRequestParams(action string, data interface{}) (queryParams map[string][]string, jsonStr []byte, err error) {
queryParams = make(map[string][]string)
err = tr.request(
"GET",
"ListZones",
record,
&result,
)
switch v := data.(type) {
case map[string][]string:
queryParams = v
jsonStr = []byte{}
case *TrafficRouteMeta:
jsonStr, _ = json.Marshal(v)
default:
if data != nil {
jsonStr, _ = json.Marshal(data)
}
}
return result, err
// 根据不同action处理参数
switch action {
case "ListZones":
if len(queryParams) == 0 && len(jsonStr) > 0 {
var params TrafficRouteListZonesParams
if err = json.Unmarshal(jsonStr, &params); err == nil && params.Key != "" {
queryParams["Key"] = []string{params.Key}
}
jsonStr = []byte{}
}
case "ListRecords":
if len(queryParams) == 0 && len(jsonStr) > 0 {
var params TrafficRouteListZonesResp
if err = json.Unmarshal(jsonStr, &params); err == nil && params.ZID != 0 {
queryParams["ZID"] = []string{strconv.Itoa(params.ZID)}
}
jsonStr = []byte{}
}
}
return
}
// request 统一请求接口
func (tr *TrafficRoute) request(method string, action string, data interface{}, result interface{}) (err error) {
jsonStr := make([]byte, 0)
if data != nil {
jsonStr, _ = json.Marshal(data)
}
var req *http.Request
// updateZoneResult, err := requestDNS("POST", map[string][]string{}, map[string]string{}, secretId, secretKey, action, body)
if action != "ListRecords" {
req, err = util.TrafficRouteSigner(method, map[string][]string{}, map[string]string{}, tr.DNS.ID, tr.DNS.Secret, action, jsonStr)
} else {
var QueryParamConv TrafficRouteMeta
jsonRes := json.Unmarshal(jsonStr, &QueryParamConv)
if jsonRes != nil {
util.Log("%v", jsonRes)
return
}
zoneID := strconv.Itoa(QueryParamConv.ZID)
QueryParam := map[string][]string{"ZID": []string{zoneID}}
req, err = util.TrafficRouteSigner(method, QueryParam, map[string]string{}, tr.DNS.ID, tr.DNS.Secret, action, []byte{})
func (tr *TrafficRoute) request(method string, action string, data interface{}, result interface{}) error {
queryParams, jsonStr, err := tr.parseRequestParams(action, data)
if err != nil {
return err
}
req, err := util.TrafficRouteSigner(method, queryParams, map[string]string{}, tr.DNS.ID, tr.DNS.Secret, action, jsonStr)
if err != nil {
return err
}
client := util.CreateHTTPClient()
resp, err := client.Do(req)
err = util.GetHTTPResponse(resp, err, result)
return err
return util.GetHTTPResponse(resp, err, result)
}