From 5fc0cd688b1a07d10f5f09011f986ca2abbecdd3 Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Thu, 20 Oct 2022 18:06:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96DNSPod=E5=92=8CAlidns?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/dnsclients/dnspod/response_base.go | 18 ++++ .../dnsclients/dnspod/response_domain_info.go | 13 +++ .../dnsclients/dnspod/response_domain_list.go | 17 +++ .../dnsclients/dnspod/response_interface.go | 8 ++ .../dnspod/response_record_create.go | 13 +++ .../dnsclients/dnspod/response_record_line.go | 9 ++ .../dnsclients/dnspod/response_record_list.go | 23 ++++ .../dnspod/response_record_modify.go | 14 +++ .../dnspod/response_record_remove.go | 7 ++ internal/dnsclients/provider_alidns.go | 33 +++--- internal/dnsclients/provider_alidns_test.go | 7 +- internal/dnsclients/provider_base.go | 1 + internal/dnsclients/provider_dnspod.go | 100 +++++++++--------- internal/dnsclients/provider_dnspod_test.go | 13 +-- 14 files changed, 202 insertions(+), 74 deletions(-) create mode 100644 internal/dnsclients/dnspod/response_base.go create mode 100644 internal/dnsclients/dnspod/response_domain_info.go create mode 100644 internal/dnsclients/dnspod/response_domain_list.go create mode 100644 internal/dnsclients/dnspod/response_interface.go create mode 100644 internal/dnsclients/dnspod/response_record_create.go create mode 100644 internal/dnsclients/dnspod/response_record_line.go create mode 100644 internal/dnsclients/dnspod/response_record_list.go create mode 100644 internal/dnsclients/dnspod/response_record_modify.go create mode 100644 internal/dnsclients/dnspod/response_record_remove.go diff --git a/internal/dnsclients/dnspod/response_base.go b/internal/dnsclients/dnspod/response_base.go new file mode 100644 index 00000000..4a3c6859 --- /dev/null +++ b/internal/dnsclients/dnspod/response_base.go @@ -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 +} diff --git a/internal/dnsclients/dnspod/response_domain_info.go b/internal/dnsclients/dnspod/response_domain_info.go new file mode 100644 index 00000000..9189e62c --- /dev/null +++ b/internal/dnsclients/dnspod/response_domain_info.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_domain_list.go b/internal/dnsclients/dnspod/response_domain_list.go new file mode 100644 index 00000000..a0b724c9 --- /dev/null +++ b/internal/dnsclients/dnspod/response_domain_list.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_interface.go b/internal/dnsclients/dnspod/response_interface.go new file mode 100644 index 00000000..2fdb6e4c --- /dev/null +++ b/internal/dnsclients/dnspod/response_interface.go @@ -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) +} diff --git a/internal/dnsclients/dnspod/response_record_create.go b/internal/dnsclients/dnspod/response_record_create.go new file mode 100644 index 00000000..ecfe67d1 --- /dev/null +++ b/internal/dnsclients/dnspod/response_record_create.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_record_line.go b/internal/dnsclients/dnspod/response_record_line.go new file mode 100644 index 00000000..03623ce2 --- /dev/null +++ b/internal/dnsclients/dnspod/response_record_line.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_record_list.go b/internal/dnsclients/dnspod/response_record_list.go new file mode 100644 index 00000000..81c38a96 --- /dev/null +++ b/internal/dnsclients/dnspod/response_record_list.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_record_modify.go b/internal/dnsclients/dnspod/response_record_modify.go new file mode 100644 index 00000000..079bcd27 --- /dev/null +++ b/internal/dnsclients/dnspod/response_record_modify.go @@ -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"` +} diff --git a/internal/dnsclients/dnspod/response_record_remove.go b/internal/dnsclients/dnspod/response_record_remove.go new file mode 100644 index 00000000..ad4e6e2c --- /dev/null +++ b/internal/dnsclients/dnspod/response_record_remove.go @@ -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 +} diff --git a/internal/dnsclients/provider_alidns.go b/internal/dnsclients/provider_alidns.go index 18d96929..9ea3e32e 100644 --- a/internal/dnsclients/provider_alidns.go +++ b/internal/dnsclients/provider_alidns.go @@ -42,14 +42,14 @@ func (this *AliDNSProvider) Auth(params maps.Map) error { // GetDomains 获取所有域名列表 func (this *AliDNSProvider) GetDomains() (domains []string, err error) { - pageNumber := 1 - size := 100 + var pageNumber = 1 + var size = 100 for { - req := alidns.CreateDescribeDomainsRequest() + var req = alidns.CreateDescribeDomainsRequest() req.PageNumber = requests.NewInteger(pageNumber) req.PageSize = requests.NewInteger(size) - resp := alidns.CreateDescribeDomainsResponse() + var resp = alidns.CreateDescribeDomainsResponse() err = this.doAPI(req, resp) if err != nil { return nil, err @@ -70,16 +70,16 @@ func (this *AliDNSProvider) GetDomains() (domains []string, err error) { // GetRecords 获取域名列表 func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) { - pageNumber := 1 - size := 100 + var pageNumber = 1 + var size = 100 for { - req := alidns.CreateDescribeDomainRecordsRequest() + var req = alidns.CreateDescribeDomainRecordsRequest() req.DomainName = domain req.PageNumber = requests.NewInteger(pageNumber) req.PageSize = requests.NewInteger(size) - resp := alidns.CreateDescribeDomainRecordsResponse() + var resp = alidns.CreateDescribeDomainRecordsResponse() err = this.doAPI(req, resp) if err != nil { return nil, err @@ -111,10 +111,10 @@ func (this *AliDNSProvider) GetRecords(domain string) (records []*dnstypes.Recor // GetRoutes 读取域名支持的线路数据 func (this *AliDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) { - req := alidns.CreateDescribeSupportLinesRequest() + var req = alidns.CreateDescribeSupportLinesRequest() req.DomainName = domain - resp := alidns.CreateDescribeSupportLinesResponse() + var resp = alidns.CreateDescribeSupportLinesResponse() err = this.doAPI(req, resp) if err != nil { return nil, err @@ -144,7 +144,7 @@ func (this *AliDNSProvider) QueryRecord(domain string, name string, recordType d // AddRecord 设置记录 func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error { - req := alidns.CreateAddDomainRecordRequest() + var req = alidns.CreateAddDomainRecordRequest() req.RR = newRecord.Name req.Type = newRecord.Type 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)) } - resp := alidns.CreateAddDomainRecordResponse() + var resp = alidns.CreateAddDomainRecordResponse() err := this.doAPI(req, resp) if err != nil { return this.WrapError(err, domain, newRecord) } if resp.IsSuccess() { + newRecord.Id = resp.RecordId return nil } @@ -169,7 +170,7 @@ func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) // UpdateRecord 修改记录 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.RR = newRecord.Name 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)) } - resp := alidns.CreateUpdateDomainRecordResponse() + var resp = alidns.CreateUpdateDomainRecordResponse() err := this.doAPI(req, resp) return this.WrapError(err, domain, newRecord) } // DeleteRecord 删除记录 func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error { - req := alidns.CreateDeleteDomainRecordRequest() + var req = alidns.CreateDeleteDomainRecordRequest() req.RecordId = record.Id - resp := alidns.CreateDeleteDomainRecordResponse() + var resp = alidns.CreateDeleteDomainRecordResponse() err := this.doAPI(req, resp) return this.WrapError(err, domain, record) } diff --git a/internal/dnsclients/provider_alidns_test.go b/internal/dnsclients/provider_alidns_test.go index 685450eb..9ff1d1ad 100644 --- a/internal/dnsclients/provider_alidns_test.go +++ b/internal/dnsclients/provider_alidns_test.go @@ -66,17 +66,18 @@ func TestAliDNSProvider_AddRecord(t *testing.T) { t.Fatal(err) } - err = provider.AddRecord("meloy.cn", &dnstypes.Record{ + var record = &dnstypes.Record{ Id: "", Name: "test", Type: dnstypes.RecordTypeA, Value: "192.168.1.100", Route: "aliyun_r_cn-beijing", - }) + } + err = provider.AddRecord("meloy.cn", record) if err != nil { t.Fatal(err) } - t.Log("ok") + t.Log("ok, record id:", record.Id) } func TestAliDNSProvider_UpdateRecord(t *testing.T) { diff --git a/internal/dnsclients/provider_base.go b/internal/dnsclients/provider_base.go index 3506ecd3..fb5bc914 100644 --- a/internal/dnsclients/provider_base.go +++ b/internal/dnsclients/provider_base.go @@ -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()) } + diff --git a/internal/dnsclients/provider_dnspod.go b/internal/dnsclients/provider_dnspod.go index a255e656..4c9a8ee1 100644 --- a/internal/dnsclients/provider_dnspod.go +++ b/internal/dnsclients/provider_dnspod.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "encoding/json" "errors" + "github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnspod" "github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes" "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "github.com/iwind/TeaGo/maps" @@ -30,6 +31,8 @@ var dnsPodHTTPClient = &http.Client{ } // DNSPodProvider DNSPod服务商 +// TODO 考虑支持线路ID +// TODO 支持自定义线路 type DNSPodProvider struct { BaseProvider @@ -59,28 +62,23 @@ func (this *DNSPodProvider) GetDomains() (domains []string, err error) { var size = 3000 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), "length": numberutils.FormatInt(size), - }) + }, resp) if err != nil { return nil, err } offset += size - var domainsSlice = domainsResp.GetSlice("domains") - if len(domainsSlice) == 0 { - break - } - - for _, domain := range domainsSlice { - domainMap := maps.NewMap(domain) - domains = append(domains, domainMap.GetString("name")) + for _, domain := range resp.Domains { + domains = append(domains, domain.Name) } // 检查是否到头 - var info = domainsResp.GetMap("info") - var recordTotal = info.GetInt("all_total") + var recordTotal = resp.Info.AllTotal if offset >= recordTotal { break } @@ -93,33 +91,31 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor var offset = 0 var size = 3000 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, "offset": numberutils.FormatInt(offset), "length": numberutils.FormatInt(size), - }) + }, resp) if err != nil { return nil, err } offset += size // 记录 - var recordSlice = recordsResp.GetSlice("records") - for _, record := range recordSlice { - recordMap := maps.NewMap(record) + for _, record := range resp.Records { records = append(records, &dnstypes.Record{ - Id: recordMap.GetString("id"), - Name: recordMap.GetString("name"), - Type: recordMap.GetString("type"), - Value: recordMap.GetString("value"), - Route: recordMap.GetString("line"), - TTL: recordMap.GetInt32("ttl"), + Id: types.String(record.Id), + Name: record.Name, + Type: record.Type, + Value: record.Value, + Route: record.Line, + TTL: types.Int32(record.TTL), }) } // 检查是否到头 - var info = recordsResp.GetMap("info") - var recordTotal = info.GetInt("record_total") + var recordTotal = types.Int(resp.Info.RecordTotal) if offset >= recordTotal { break } @@ -129,24 +125,25 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor // GetRoutes 读取线路数据 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, - }) + }, domainInfoResp) if err != nil { return nil, err } - domainInfo := infoResp.GetMap("domain") - grade := domainInfo.GetString("grade") + var grade = domainInfoResp.Domain.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_grade": grade, - }) + }, linesResp) if err != nil { return nil, err } - lines := linesResp.GetSlice("lines") + var lines = linesResp.Lines if len(lines) == 0 { return nil, nil } @@ -196,8 +193,13 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record) if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL { args["ttl"] = types.String(newRecord.TTL) } - _, err := this.post("/Record.Create", args) - return this.WrapError(err, domain, newRecord) + var resp = new(dnspod.RecordCreateResponse) + 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 修改记录 @@ -225,7 +227,8 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record, if newRecord.TTL > 0 && newRecord.TTL <= DNSPodMaxTTL { 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) } @@ -235,16 +238,17 @@ func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) 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, "record_id": record.Id, - }) + }, resp) 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 lang = "cn" 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())) 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("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) if err != nil { - return nil, err + return err } defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + return err } - var m = maps.Map{} - err = json.Unmarshal(body, &m) + err = json.Unmarshal(body, &respPtr) if err != nil { - return nil, err + return err } - var status = m.GetMap("status") - var code = status.GetString("code") - if code != "1" { - return nil, errors.New("API response error: code: " + code + ", message: " + status.GetString("message")) + if !respPtr.IsOk() { + code, message := respPtr.LastError() + return errors.New("API response error: code: " + code + ", message: " + message) } - return m, nil + return nil } // DefaultRoute 默认线路 diff --git a/internal/dnsclients/provider_dnspod_test.go b/internal/dnsclients/provider_dnspod_test.go index 956eba30..2a256419 100644 --- a/internal/dnsclients/provider_dnspod_test.go +++ b/internal/dnsclients/provider_dnspod_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -const DNSPodTestDomain = "yun4s.cn" +const DNSPodTestDomain = "goedge.cloud" func TestDNSPodProvider_GetDomains(t *testing.T) { provider, _, err := testDNSPodProvider() @@ -61,17 +61,18 @@ func TestDNSPodProvider_AddRecord(t *testing.T) { route = "Default" } - err = provider.AddRecord(DNSPodTestDomain, &dnstypes.Record{ + var record = &dnstypes.Record{ Type: dnstypes.RecordTypeCNAME, Name: "hello-forward", Value: "hello." + DNSPodTestDomain, Route: route, TTL: 600, - }) + } + err = provider.AddRecord(DNSPodTestDomain, record) if err != nil { t.Fatal(err) } - t.Log("ok") + t.Log("ok, record id:", record.Id) } func TestDNSPodProvider_UpdateRecord(t *testing.T) { @@ -81,7 +82,7 @@ func TestDNSPodProvider_UpdateRecord(t *testing.T) { } var route = "联通" - var id = "1093875360" + var id = "1224507933" if isInternational { route = "Default" id = "28507333" @@ -107,7 +108,7 @@ func TestDNSPodProvider_DeleteRecord(t *testing.T) { t.Fatal(err) } - var id = "1093875360" + var id = "1224507933" if isInternational { id = "28507333" }