优化DNSPod和Alidns相关代码

This commit is contained in:
GoEdgeLab
2022-10-20 18:06:27 +08:00
parent 0dc5478bc6
commit 5fc0cd688b
14 changed files with 202 additions and 74 deletions

View File

@@ -0,0 +1,18 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnspod
type BaseResponse struct {
Status struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"status"`
}
func (this *BaseResponse) IsOk() bool {
return this.Status.Code == "1"
}
func (this *BaseResponse) LastError() (code string, message string) {
return this.Status.Code, this.Status.Message
}

View File

@@ -0,0 +1,13 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type DomainInfoResponse struct {
BaseResponse
Domain struct {
Id any `json:"id"`
Name string `json:"name"`
Grade string `json:"grade"`
} `json:"domain"`
}

View File

@@ -0,0 +1,17 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type DomainListResponse struct {
BaseResponse
Info struct {
DomainTotal int `json:"domain_total"`
AllTotal int `json:"all_total"`
MineTotal int `json:"mine_total"`
} `json:"info"`
Domains []struct {
Name string `json:"name"`
} `json:"domains"`
}

View File

@@ -0,0 +1,8 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnspod
type ResponseInterface interface {
IsOk() bool
LastError() (code string, message string)
}

View File

@@ -0,0 +1,13 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type RecordCreateResponse struct {
BaseResponse
Record struct {
Id any `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
} `json:"record"`
}

View File

@@ -0,0 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type RecordLineResponse struct {
BaseResponse
Lines []string `json:"lines"`
}

View File

@@ -0,0 +1,23 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type RecordListResponse struct {
BaseResponse
Info struct {
SubDomains string `json:"sub_domains"`
RecordTotal string `json:"record_total"`
RecordsNum string `json:"records_num"`
} `json:"info"`
Records []struct {
Id any `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Value string `json:"value"`
Line string `json:"line"`
LineId string `json:"line_id"`
TTL string `json:"ttl"`
} `json:"records"`
}

View File

@@ -0,0 +1,14 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type RecordModifyResponse struct {
BaseResponse
Record struct {
Id any `json:"id"`
Name string `json:"name"`
Value string `json:"value"`
Status string `json:"status"`
} `json:"record"`
}

View File

@@ -0,0 +1,7 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnspod
type RecordRemoveResponse struct {
BaseResponse
}

View File

@@ -42,14 +42,14 @@ func (this *AliDNSProvider) Auth(params maps.Map) error {
// GetDomains 获取所有域名列表 // GetDomains 获取所有域名列表
func (this *AliDNSProvider) GetDomains() (domains []string, err error) { func (this *AliDNSProvider) GetDomains() (domains []string, err error) {
pageNumber := 1 var pageNumber = 1
size := 100 var size = 100
for { for {
req := alidns.CreateDescribeDomainsRequest() var req = alidns.CreateDescribeDomainsRequest()
req.PageNumber = requests.NewInteger(pageNumber) req.PageNumber = requests.NewInteger(pageNumber)
req.PageSize = requests.NewInteger(size) req.PageSize = requests.NewInteger(size)
resp := alidns.CreateDescribeDomainsResponse() var resp = alidns.CreateDescribeDomainsResponse()
err = this.doAPI(req, resp) err = this.doAPI(req, resp)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -70,16 +70,16 @@ func (this *AliDNSProvider) GetDomains() (domains []string, err error) {
// GetRecords 获取域名列表 // GetRecords 获取域名列表
func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) { func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
pageNumber := 1 var pageNumber = 1
size := 100 var size = 100
for { for {
req := alidns.CreateDescribeDomainRecordsRequest() var req = alidns.CreateDescribeDomainRecordsRequest()
req.DomainName = domain req.DomainName = domain
req.PageNumber = requests.NewInteger(pageNumber) req.PageNumber = requests.NewInteger(pageNumber)
req.PageSize = requests.NewInteger(size) req.PageSize = requests.NewInteger(size)
resp := alidns.CreateDescribeDomainRecordsResponse() var resp = alidns.CreateDescribeDomainRecordsResponse()
err = this.doAPI(req, resp) err = this.doAPI(req, resp)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -111,10 +111,10 @@ func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Recor
// GetRoutes 读取域名支持的线路数据 // GetRoutes 读取域名支持的线路数据
func (this *AliDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) { func (this *AliDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
req := alidns.CreateDescribeSupportLinesRequest() var req = alidns.CreateDescribeSupportLinesRequest()
req.DomainName = domain req.DomainName = domain
resp := alidns.CreateDescribeSupportLinesResponse() var resp = alidns.CreateDescribeSupportLinesResponse()
err = this.doAPI(req, resp) err = this.doAPI(req, resp)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -144,7 +144,7 @@ func (this *AliDNSProvider) QueryRecord(domain string, name string, recordType d
// AddRecord 设置记录 // AddRecord 设置记录
func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error { func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
req := alidns.CreateAddDomainRecordRequest() var req = alidns.CreateAddDomainRecordRequest()
req.RR = newRecord.Name req.RR = newRecord.Name
req.Type = newRecord.Type req.Type = newRecord.Type
req.Value = newRecord.Value req.Value = newRecord.Value
@@ -155,12 +155,13 @@ func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record)
req.TTL = requests.NewInteger(types.Int(newRecord.TTL)) req.TTL = requests.NewInteger(types.Int(newRecord.TTL))
} }
resp := alidns.CreateAddDomainRecordResponse() var resp = alidns.CreateAddDomainRecordResponse()
err := this.doAPI(req, resp) err := this.doAPI(req, resp)
if err != nil { if err != nil {
return this.WrapError(err, domain, newRecord) return this.WrapError(err, domain, newRecord)
} }
if resp.IsSuccess() { if resp.IsSuccess() {
newRecord.Id = resp.RecordId
return nil return nil
} }
@@ -169,7 +170,7 @@ func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record)
// UpdateRecord 修改记录 // UpdateRecord 修改记录
func (this *AliDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error { func (this *AliDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
req := alidns.CreateUpdateDomainRecordRequest() var req = alidns.CreateUpdateDomainRecordRequest()
req.RecordId = record.Id req.RecordId = record.Id
req.RR = newRecord.Name req.RR = newRecord.Name
req.Type = newRecord.Type req.Type = newRecord.Type
@@ -180,17 +181,17 @@ func (this *AliDNSProvider) UpdateRecord(domain string, record *dnstypes.Record,
req.TTL = requests.NewInteger(types.Int(newRecord.TTL)) req.TTL = requests.NewInteger(types.Int(newRecord.TTL))
} }
resp := alidns.CreateUpdateDomainRecordResponse() var resp = alidns.CreateUpdateDomainRecordResponse()
err := this.doAPI(req, resp) err := this.doAPI(req, resp)
return this.WrapError(err, domain, newRecord) return this.WrapError(err, domain, newRecord)
} }
// DeleteRecord 删除记录 // DeleteRecord 删除记录
func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error { func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
req := alidns.CreateDeleteDomainRecordRequest() var req = alidns.CreateDeleteDomainRecordRequest()
req.RecordId = record.Id req.RecordId = record.Id
resp := alidns.CreateDeleteDomainRecordResponse() var resp = alidns.CreateDeleteDomainRecordResponse()
err := this.doAPI(req, resp) err := this.doAPI(req, resp)
return this.WrapError(err, domain, record) return this.WrapError(err, domain, record)
} }

View File

@@ -66,17 +66,18 @@ func TestAliDNSProvider_AddRecord(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = provider.AddRecord("meloy.cn", &dnstypes.Record{ var record = &dnstypes.Record{
Id: "", Id: "",
Name: "test", Name: "test",
Type: dnstypes.RecordTypeA, Type: dnstypes.RecordTypeA,
Value: "192.168.1.100", Value: "192.168.1.100",
Route: "aliyun_r_cn-beijing", Route: "aliyun_r_cn-beijing",
}) }
err = provider.AddRecord("meloy.cn", record)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") t.Log("ok, record id:", record.Id)
} }
func TestAliDNSProvider_UpdateRecord(t *testing.T) { func TestAliDNSProvider_UpdateRecord(t *testing.T) {

View File

@@ -27,3 +27,4 @@ func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.R
} }
return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error()) return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error())
} }

View File

@@ -4,6 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnspod"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes" "github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -30,6 +31,8 @@ var dnsPodHTTPClient = &http.Client{
} }
// DNSPodProvider DNSPod服务商 // DNSPodProvider DNSPod服务商
// TODO 考虑支持线路ID
// TODO 支持自定义线路
type DNSPodProvider struct { type DNSPodProvider struct {
BaseProvider BaseProvider
@@ -59,28 +62,23 @@ func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
var size = 3000 var size = 3000
for { for {
domainsResp, err := this.post("/Domain.List", map[string]string{ var resp = new(dnspod.DomainListResponse)
err := this.doAPI("/Domain.List", map[string]string{
"offset": numberutils.FormatInt(offset), "offset": numberutils.FormatInt(offset),
"length": numberutils.FormatInt(size), "length": numberutils.FormatInt(size),
}) }, resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
offset += size offset += size
var domainsSlice = domainsResp.GetSlice("domains") for _, domain := range resp.Domains {
if len(domainsSlice) == 0 { domains = append(domains, domain.Name)
break
}
for _, domain := range domainsSlice {
domainMap := maps.NewMap(domain)
domains = append(domains, domainMap.GetString("name"))
} }
// 检查是否到头 // 检查是否到头
var info = domainsResp.GetMap("info") var recordTotal = resp.Info.AllTotal
var recordTotal = info.GetInt("all_total")
if offset >= recordTotal { if offset >= recordTotal {
break break
} }
@@ -93,33 +91,31 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
var offset = 0 var offset = 0
var size = 3000 var size = 3000
for { for {
recordsResp, err := this.post("/Record.List", map[string]string{ var resp = new(dnspod.RecordListResponse)
err := this.doAPI("/Record.List", map[string]string{
"domain": domain, "domain": domain,
"offset": numberutils.FormatInt(offset), "offset": numberutils.FormatInt(offset),
"length": numberutils.FormatInt(size), "length": numberutils.FormatInt(size),
}) }, resp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
offset += size offset += size
// 记录 // 记录
var recordSlice = recordsResp.GetSlice("records") for _, record := range resp.Records {
for _, record := range recordSlice {
recordMap := maps.NewMap(record)
records = append(records, &dnstypes.Record{ records = append(records, &dnstypes.Record{
Id: recordMap.GetString("id"), Id: types.String(record.Id),
Name: recordMap.GetString("name"), Name: record.Name,
Type: recordMap.GetString("type"), Type: record.Type,
Value: recordMap.GetString("value"), Value: record.Value,
Route: recordMap.GetString("line"), Route: record.Line,
TTL: recordMap.GetInt32("ttl"), TTL: types.Int32(record.TTL),
}) })
} }
// 检查是否到头 // 检查是否到头
var info = recordsResp.GetMap("info") var recordTotal = types.Int(resp.Info.RecordTotal)
var recordTotal = info.GetInt("record_total")
if offset >= recordTotal { if offset >= recordTotal {
break break
} }
@@ -129,24 +125,25 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
// GetRoutes 读取线路数据 // GetRoutes 读取线路数据
func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) { func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
infoResp, err := this.post("/Domain.Info", map[string]string{ var domainInfoResp = new(dnspod.DomainInfoResponse)
err = this.doAPI("/Domain.Info", map[string]string{
"domain": domain, "domain": domain,
}) }, domainInfoResp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
domainInfo := infoResp.GetMap("domain") var grade = domainInfoResp.Domain.Grade
grade := domainInfo.GetString("grade")
linesResp, err := this.post("/Record.Line", map[string]string{ var linesResp = new(dnspod.RecordLineResponse)
err = this.doAPI("/Record.Line", map[string]string{
"domain": domain, "domain": domain,
"domain_grade": grade, "domain_grade": grade,
}) }, linesResp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
lines := linesResp.GetSlice("lines") var lines = linesResp.Lines
if len(lines) == 0 { if len(lines) == 0 {
return nil, nil return nil, nil
} }
@@ -196,8 +193,13 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL { if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL {
args["ttl"] = types.String(newRecord.TTL) args["ttl"] = types.String(newRecord.TTL)
} }
_, err := this.post("/Record.Create", args) var resp = new(dnspod.RecordCreateResponse)
return this.WrapError(err, domain, newRecord) err := this.doAPI("/Record.Create", args, resp)
if err != nil {
return this.WrapError(err, domain, newRecord)
}
newRecord.Id = types.String(resp.Record.Id)
return nil
} }
// UpdateRecord 修改记录 // UpdateRecord 修改记录
@@ -225,7 +227,8 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL { if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL {
args["ttl"] = types.String(newRecord.TTL) args["ttl"] = types.String(newRecord.TTL)
} }
_, err := this.post("/Record.Modify", args) var resp = new(dnspod.RecordModifyResponse)
err := this.doAPI("/Record.Modify", args, resp)
return this.WrapError(err, domain, newRecord) return this.WrapError(err, domain, newRecord)
} }
@@ -235,16 +238,17 @@ func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record)
return errors.New("invalid record to delete") return errors.New("invalid record to delete")
} }
_, err := this.post("/Record.Remove", map[string]string{ var resp = new(dnspod.RecordRemoveResponse)
err := this.doAPI("/Record.Remove", map[string]string{
"domain": domain, "domain": domain,
"record_id": record.Id, "record_id": record.Id,
}) }, resp)
return this.WrapError(err, domain, record) return this.WrapError(err, domain, record)
} }
// 发送请求 // 发送请求
func (this *DNSPodProvider) post(path string, params map[string]string) (maps.Map, error) { func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr dnspod.ResponseInterface) error {
var apiHost = "https://dnsapi.cn" var apiHost = "https://dnsapi.cn"
var lang = "cn" var lang = "cn"
if this.isInternational() { // 国际版 if this.isInternational() { // 国际版
@@ -263,7 +267,7 @@ func (this *DNSPodProvider) post(path string, params map[string]string) (maps.Ma
req, err := http.NewRequest(http.MethodPost, apiHost+path, strings.NewReader(query.Encode())) req, err := http.NewRequest(http.MethodPost, apiHost+path, strings.NewReader(query.Encode()))
if err != nil { if err != nil {
return nil, err return errors.New("create request failed: " + err.Error())
} }
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("User-Agent", "GoEdge-Client/1.0.0 (iwind.liu@gmail.com)") req.Header.Set("User-Agent", "GoEdge-Client/1.0.0 (iwind.liu@gmail.com)")
@@ -271,27 +275,25 @@ func (this *DNSPodProvider) post(path string, params map[string]string) (maps.Ma
resp, err := dnsPodHTTPClient.Do(req) resp, err := dnsPodHTTPClient.Do(req)
if err != nil { if err != nil {
return nil, err return err
} }
defer func() { defer func() {
_ = resp.Body.Close() _ = resp.Body.Close()
}() }()
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return err
} }
var m = maps.Map{} err = json.Unmarshal(body, &respPtr)
err = json.Unmarshal(body, &m)
if err != nil { if err != nil {
return nil, err return err
} }
var status = m.GetMap("status") if !respPtr.IsOk() {
var code = status.GetString("code") code, message := respPtr.LastError()
if code != "1" { return errors.New("API response error: code: " + code + ", message: " + message)
return nil, errors.New("API response error: code: " + code + ", message: " + status.GetString("message"))
} }
return m, nil return nil
} }
// DefaultRoute 默认线路 // DefaultRoute 默认线路

View File

@@ -10,7 +10,7 @@ import (
"testing" "testing"
) )
const DNSPodTestDomain = "yun4s.cn" const DNSPodTestDomain = "goedge.cloud"
func TestDNSPodProvider_GetDomains(t *testing.T) { func TestDNSPodProvider_GetDomains(t *testing.T) {
provider, _, err := testDNSPodProvider() provider, _, err := testDNSPodProvider()
@@ -61,17 +61,18 @@ func TestDNSPodProvider_AddRecord(t *testing.T) {
route = "Default" route = "Default"
} }
err = provider.AddRecord(DNSPodTestDomain, &dnstypes.Record{ var record = &dnstypes.Record{
Type: dnstypes.RecordTypeCNAME, Type: dnstypes.RecordTypeCNAME,
Name: "hello-forward", Name: "hello-forward",
Value: "hello." + DNSPodTestDomain, Value: "hello." + DNSPodTestDomain,
Route: route, Route: route,
TTL: 600, TTL: 600,
}) }
err = provider.AddRecord(DNSPodTestDomain, record)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") t.Log("ok, record id:", record.Id)
} }
func TestDNSPodProvider_UpdateRecord(t *testing.T) { func TestDNSPodProvider_UpdateRecord(t *testing.T) {
@@ -81,7 +82,7 @@ func TestDNSPodProvider_UpdateRecord(t *testing.T) {
} }
var route = "联通" var route = "联通"
var id = "1093875360" var id = "1224507933"
if isInternational { if isInternational {
route = "Default" route = "Default"
id = "28507333" id = "28507333"
@@ -107,7 +108,7 @@ func TestDNSPodProvider_DeleteRecord(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
var id = "1093875360" var id = "1224507933"
if isInternational { if isInternational {
id = "28507333" id = "28507333"
} }