mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			1614 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1614 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
						||
 | 
						||
package dnsclients
 | 
						||
 | 
						||
import (
 | 
						||
	"bytes"
 | 
						||
	"crypto/hmac"
 | 
						||
	"crypto/sha256"
 | 
						||
	"crypto/tls"
 | 
						||
	"encoding/json"
 | 
						||
	"fmt"
 | 
						||
	"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
 | 
						||
	"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/huaweidns"
 | 
						||
	"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
						||
	"github.com/iwind/TeaGo/maps"
 | 
						||
	"github.com/iwind/TeaGo/types"
 | 
						||
	"io"
 | 
						||
	"net/http"
 | 
						||
	"net/url"
 | 
						||
	"regexp"
 | 
						||
	"sort"
 | 
						||
	"strconv"
 | 
						||
	"strings"
 | 
						||
	"time"
 | 
						||
)
 | 
						||
 | 
						||
// HuaweiDNSDefaultEndpoint 默认Endpoint
 | 
						||
// 所有Endpoints:https://developer.huaweicloud.com/endpoint?DNS
 | 
						||
const HuaweiDNSDefaultEndpoint = "https://dns.cn-north-4.myhuaweicloud.com/"
 | 
						||
 | 
						||
var huaweiDNSHTTPClient = &http.Client{
 | 
						||
	Timeout: 10 * time.Second,
 | 
						||
	Transport: &http.Transport{
 | 
						||
		TLSClientConfig: &tls.Config{
 | 
						||
			InsecureSkipVerify: true,
 | 
						||
		},
 | 
						||
	},
 | 
						||
}
 | 
						||
 | 
						||
// HuaweiDNSProvider 华为云DNS
 | 
						||
// 相关文档链接:https://support.huaweicloud.com/api-dns/dns_api_62001.html
 | 
						||
type HuaweiDNSProvider struct {
 | 
						||
	BaseProvider
 | 
						||
 | 
						||
	ProviderId int64
 | 
						||
 | 
						||
	accessKeyId     string
 | 
						||
	accessKeySecret string
 | 
						||
	endpoint        string
 | 
						||
 | 
						||
	endpointRegionReg *regexp.Regexp
 | 
						||
	endpointDomainReg *regexp.Regexp
 | 
						||
}
 | 
						||
 | 
						||
// Auth 认证
 | 
						||
func (this *HuaweiDNSProvider) Auth(params maps.Map) error {
 | 
						||
	this.accessKeyId = params.GetString("accessKeyId")
 | 
						||
	this.accessKeySecret = params.GetString("accessKeySecret")
 | 
						||
	if len(this.accessKeyId) == 0 {
 | 
						||
		return errors.New("'accessKeyId' should not be empty")
 | 
						||
	}
 | 
						||
	if len(this.accessKeySecret) == 0 {
 | 
						||
		return errors.New("'accessKeySecret' should not be empty")
 | 
						||
	}
 | 
						||
	this.endpoint = params.GetString("endpoint")
 | 
						||
 | 
						||
	// endpoint相关正则
 | 
						||
	this.endpointRegionReg = regexp.MustCompile(`^[\w-]+$`)
 | 
						||
	this.endpointDomainReg = regexp.MustCompile(`^([\w-]+\.)+[\w-]+$`)
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// GetDomains 获取所有域名列表
 | 
						||
func (this *HuaweiDNSProvider) GetDomains() (domains []string, err error) {
 | 
						||
	var resp = new(huaweidns.ZonesResponse)
 | 
						||
	err = this.doAPI(http.MethodGet, "/v2/zones", map[string]string{}, nil, resp)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	for _, zone := range resp.Zones {
 | 
						||
		zone.Name = strings.TrimSuffix(zone.Name, ".")
 | 
						||
		domains = append(domains, zone.Name)
 | 
						||
	}
 | 
						||
	return
 | 
						||
}
 | 
						||
 | 
						||
// GetRecords 获取域名解析记录列表
 | 
						||
func (this *HuaweiDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
 | 
						||
	zoneId, err := this.findZoneIdWithDomain(domain)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	var limit = 500
 | 
						||
	for i := 0; i <= 100; i++ {
 | 
						||
		var resp = new(huaweidns.ZoneRecordSetsResponse)
 | 
						||
		err := this.doAPI(http.MethodGet, "/v2.1/zones/"+zoneId+"/recordsets", map[string]string{
 | 
						||
			"offset": types.String(i * limit),
 | 
						||
			"limit":  types.String(limit),
 | 
						||
		}, map[string]interface{}{}, resp)
 | 
						||
		if err != nil {
 | 
						||
			return nil, err
 | 
						||
		}
 | 
						||
		if len(resp.RecordSets) == 0 {
 | 
						||
			break
 | 
						||
		}
 | 
						||
		for _, recordSet := range resp.RecordSets {
 | 
						||
			for _, value := range recordSet.Records {
 | 
						||
				name := strings.TrimSuffix(recordSet.Name, "."+domain+".")
 | 
						||
 | 
						||
				records = append(records, &dnstypes.Record{
 | 
						||
					Id:    recordSet.Id + "@" + value,
 | 
						||
					Name:  name,
 | 
						||
					Type:  recordSet.Type,
 | 
						||
					Value: value,
 | 
						||
					Route: recordSet.Line,
 | 
						||
					TTL:   types.Int32(recordSet.Ttl),
 | 
						||
				})
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	return
 | 
						||
}
 | 
						||
 | 
						||
// GetRoutes 读取域名支持的线路数据
 | 
						||
func (this *HuaweiDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
 | 
						||
	// 自定义线路
 | 
						||
	var resp = new(huaweidns.CustomLinesResponse)
 | 
						||
	err = this.doAPI(http.MethodGet, "/v2.1/customlines", map[string]string{}, maps.Map{}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
	for _, line := range resp.Lines {
 | 
						||
		routes = append(routes, &dnstypes.Route{
 | 
						||
			Name: line.Name,
 | 
						||
			Code: line.LineId,
 | 
						||
		})
 | 
						||
	}
 | 
						||
 | 
						||
	// 官方线路列表
 | 
						||
	// 参考:https://support.huaweicloud.com/api-dns/zh-cn_topic_0085546214.html
 | 
						||
 | 
						||
	// 运营商线路
 | 
						||
	routes = append(routes, []*dnstypes.Route{
 | 
						||
		{
 | 
						||
			Code: "default_view",
 | 
						||
			Name: "全网默认",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Dianxin",
 | 
						||
			Name: "电信",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Liantong",
 | 
						||
			Name: "联通",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Yidong",
 | 
						||
			Name: "移动",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Jiaoyuwang",
 | 
						||
			Name: "教育网",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Tietong",
 | 
						||
			Name: "铁通",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Pengboshi",
 | 
						||
 | 
						||
			Name: "鹏博士",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "CN",
 | 
						||
			Name: "中国",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "Abroad",
 | 
						||
			Name: "全球",
 | 
						||
		},
 | 
						||
	}...)
 | 
						||
 | 
						||
	// 地域线路细分(全球)
 | 
						||
	routes = append(routes, []*dnstypes.Route{
 | 
						||
		{
 | 
						||
			Code: "AP",
 | 
						||
			Name: "全球_亚太地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AE",
 | 
						||
 | 
						||
			Name: "全球_阿联酋",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AM",
 | 
						||
			Name: "全球_亚美尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AZ",
 | 
						||
			Name: "全球_阿塞拜疆",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BD",
 | 
						||
			Name: "全球_孟加拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BH",
 | 
						||
			Name: "全球_巴林",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BN",
 | 
						||
			Name: "全球_文莱",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BT",
 | 
						||
			Name: "全球_不丹",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CX",
 | 
						||
			Name: "全球_圣诞岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GE",
 | 
						||
			Name: "全球_格鲁吉亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "HK",
 | 
						||
			Name: "全球_中国香港",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ID",
 | 
						||
			Name: "全球_印度尼西亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IN",
 | 
						||
			Name: "全球_印度",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "IQ",
 | 
						||
			Name: "全球_伊拉克",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "JO",
 | 
						||
			Name: "全球_约旦",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "KG",
 | 
						||
			Name: "全球_吉尔吉斯斯坦",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "KH",
 | 
						||
			Name: "全球_柬埔寨",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "KW",
 | 
						||
			Name: "全球_科威特",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "KZ",
 | 
						||
			Name: "全球_哈萨克斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LB",
 | 
						||
			Name: "全球_黎巴嫩",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LK",
 | 
						||
			Name: "全球_斯里兰卡",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MM",
 | 
						||
			Name: "全球_缅甸",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MN",
 | 
						||
			Name: "全球_蒙古",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MO",
 | 
						||
			Name: "全球_中国澳门",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MV",
 | 
						||
			Name: "全球_马尔代夫",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MY",
 | 
						||
			Name: "全球_马来西亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NP",
 | 
						||
			Name: "全球_尼泊尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "OM",
 | 
						||
			Name: "全球_阿曼",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PH",
 | 
						||
			Name: "全球_菲律宾",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PK",
 | 
						||
			Name: "全球_巴基斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PS",
 | 
						||
			Name: "全球_巴勒斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "QA",
 | 
						||
			Name: "全球_卡塔尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SA",
 | 
						||
			Name: "全球_沙特阿拉伯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SG",
 | 
						||
			Name: "全球_新加坡",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TH",
 | 
						||
			Name: "全球_泰国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TJ",
 | 
						||
			Name: "全球_塔吉克斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TL",
 | 
						||
			Name: "全球_东帝汶",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TM",
 | 
						||
			Name: "全球_土库曼斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TW",
 | 
						||
			Name: "全球_中国台湾",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "UZ",
 | 
						||
			Name: "全球_乌兹别克斯坦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VN",
 | 
						||
			Name: "全球_越南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "YE",
 | 
						||
			Name: "全球_也门",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AS",
 | 
						||
			Name: "全球_美属萨摩亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CK",
 | 
						||
			Name: "全球_库克群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "FM",
 | 
						||
			Name: "全球_密克罗尼西亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GU",
 | 
						||
			Name: "全球_关岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KI",
 | 
						||
			Name: "全球_基里巴斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MH",
 | 
						||
			Name: "全球_马绍尔群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MP",
 | 
						||
			Name: "全球_北马里亚纳群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NC",
 | 
						||
			Name: "全球_新喀里多尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NF",
 | 
						||
			Name: "全球_诺福克岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NR",
 | 
						||
			Name: "全球_瑙鲁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PF",
 | 
						||
			Name: "全球_法属波利尼西亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PG",
 | 
						||
			Name: "全球_巴布亚新几内亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PW",
 | 
						||
			Name: "全球_帕劳",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SB",
 | 
						||
			Name: "全球_所罗门群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TK",
 | 
						||
			Name: "全球_托克劳群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TO",
 | 
						||
			Name: "全球_汤加",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TV",
 | 
						||
			Name: "全球_图瓦卢",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VU",
 | 
						||
			Name: "全球_瓦努阿图",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "WS",
 | 
						||
			Name: "全球_萨摩亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CY",
 | 
						||
			Name: "全球_塞浦路斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IL",
 | 
						||
			Name: "全球_以色列",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "JP",
 | 
						||
			Name: "全球_日本",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KR",
 | 
						||
			Name: "全球_韩国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TR",
 | 
						||
			Name: "全球_土耳其",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IR",
 | 
						||
			Name: "全球_伊朗",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SY",
 | 
						||
			Name: "全球_叙利亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CN",
 | 
						||
			Name: "全球_中国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "OA",
 | 
						||
			Name: "全球_大洋洲",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AU",
 | 
						||
			Name: "全球_澳大利亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NZ",
 | 
						||
			Name: "全球_新西兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "EU",
 | 
						||
			Name: "全球_欧洲",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IO",
 | 
						||
			Name: "全球_英属印度洋领地",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BY",
 | 
						||
			Name: "全球_白俄罗斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "UA",
 | 
						||
			Name: "全球_乌克兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "RU",
 | 
						||
			Name: "全球_俄罗斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AD",
 | 
						||
			Name: "全球_安道尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AL",
 | 
						||
			Name: "全球_阿尔巴尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AT",
 | 
						||
			Name: "全球_奥地利",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AX",
 | 
						||
			Name: "全球_奥兰群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BE",
 | 
						||
			Name: "全球_比利时",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BG",
 | 
						||
			Name: "全球_保加利亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CH",
 | 
						||
			Name: "全球_瑞士",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CZ",
 | 
						||
			Name: "全球_捷克",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DE",
 | 
						||
			Name: "全球_德国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DK",
 | 
						||
			Name: "全球_丹麦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "EE",
 | 
						||
			Name: "全球_爱沙尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ES",
 | 
						||
			Name: "全球_西班牙",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "FI",
 | 
						||
			Name: "全球_芬兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "FO",
 | 
						||
			Name: "全球_法罗群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "FR",
 | 
						||
			Name: "全球_法国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GB",
 | 
						||
			Name: "全球_英国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GG",
 | 
						||
			Name: "全球_根西岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GI",
 | 
						||
			Name: "全球_直布罗陀",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GR",
 | 
						||
			Name: "全球_希腊",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "HR",
 | 
						||
			Name: "全球_克罗地亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "HU",
 | 
						||
			Name: "全球_匈牙利",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IE",
 | 
						||
			Name: "全球_爱尔兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IM",
 | 
						||
			Name: "全球_马恩岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IS",
 | 
						||
			Name: "全球_冰岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "IT",
 | 
						||
			Name: "全球_意大利",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "JE",
 | 
						||
			Name: "全球_泽西岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LI",
 | 
						||
			Name: "全球_列支敦士登",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LT",
 | 
						||
			Name: "全球_立陶宛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LU",
 | 
						||
			Name: "全球_卢森堡",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LV",
 | 
						||
			Name: "全球_拉脱维亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MC",
 | 
						||
			Name: "全球_摩纳哥",
 | 
						||
		},
 | 
						||
 | 
						||
		{
 | 
						||
			Code: "MD",
 | 
						||
			Name: "全球_摩尔多瓦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ME",
 | 
						||
			Name: "全球_黑山",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MK",
 | 
						||
			Name: "全球_北马其顿",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MT",
 | 
						||
			Name: "全球_马耳他",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NL",
 | 
						||
			Name: "全球_荷兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NO",
 | 
						||
			Name: "全球_挪威",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PL",
 | 
						||
			Name: "全球_波兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PT",
 | 
						||
			Name: "全球_葡萄牙",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "RO",
 | 
						||
			Name: "全球_罗马尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "RS",
 | 
						||
			Name: "全球_塞尔维亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SE",
 | 
						||
			Name: "全球_瑞典",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SI",
 | 
						||
			Name: "全球_斯洛文尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SK",
 | 
						||
			Name: "全球_斯洛伐克",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SM",
 | 
						||
			Name: "全球_圣马力诺",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VA",
 | 
						||
			Name: "全球_梵蒂冈",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "XK",
 | 
						||
			Name: "全球_科索沃",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GL",
 | 
						||
			Name: "全球_格陵兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NA",
 | 
						||
			Name: "全球_北美洲",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AG",
 | 
						||
			Name: "全球_安提瓜和巴布达",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BB",
 | 
						||
			Name: "全球_巴巴多斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BS",
 | 
						||
			Name: "全球_巴哈马",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BZ",
 | 
						||
			Name: "全球_伯利兹",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CR",
 | 
						||
			Name: "全球_哥斯达黎加",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DM",
 | 
						||
			Name: "全球_多米尼克",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DO",
 | 
						||
			Name: "全球_多米尼加",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GD",
 | 
						||
			Name: "全球_格林纳达",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GT",
 | 
						||
			Name: "全球_危地马拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "HN",
 | 
						||
			Name: "全球_洪都拉斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "HT",
 | 
						||
			Name: "全球_海地",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "JM",
 | 
						||
			Name: "全球_牙买加",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KN",
 | 
						||
			Name: "全球_圣基茨和尼维斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KY",
 | 
						||
			Name: "全球_开曼群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LC",
 | 
						||
			Name: "全球_圣卢西亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MX",
 | 
						||
			Name: "全球_墨西哥",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NI",
 | 
						||
			Name: "全球_尼加拉瓜",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PA",
 | 
						||
			Name: "全球_巴拿马",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PR",
 | 
						||
			Name: "全球_波多黎各",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SV",
 | 
						||
			Name: "全球_萨尔瓦多",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TC",
 | 
						||
			Name: "全球_特克斯和凯科斯群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TT",
 | 
						||
			Name: "全球_特立尼达和多巴哥",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VG",
 | 
						||
			Name: "全球_英属维尔京群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VI",
 | 
						||
			Name: "全球_美属维尔京群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CA",
 | 
						||
			Name: "全球_加拿大",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "US",
 | 
						||
			Name: "全球_美国",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VC",
 | 
						||
			Name: "全球_圣文森特和格林纳丁斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PM",
 | 
						||
			Name: "全球_圣皮埃尔和密克隆群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AN",
 | 
						||
			Name: "全球_荷属安的列斯群岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CU",
 | 
						||
			Name: "全球_古巴",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GL",
 | 
						||
			Name: "全球_格陵兰岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LA",
 | 
						||
			Name: "全球_南美洲",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AI",
 | 
						||
			Name: "全球_安圭拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AW",
 | 
						||
			Name: "全球_阿鲁巴",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BL",
 | 
						||
			Name: "全球_圣巴泰勒米岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BM",
 | 
						||
			Name: "全球_百慕大",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GP",
 | 
						||
			Name: "全球_瓜德罗普",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MS",
 | 
						||
			Name: "全球_蒙特塞拉特岛",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AR",
 | 
						||
			Name: "全球_阿根廷",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BO",
 | 
						||
			Name: "全球_玻利维亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BR",
 | 
						||
			Name: "全球_巴西",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CL",
 | 
						||
			Name: "全球_智利",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CO",
 | 
						||
			Name: "全球_哥伦比亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CW",
 | 
						||
			Name: "全球_库拉索",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "EC",
 | 
						||
			Name: "全球_厄瓜多尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GF",
 | 
						||
			Name: "全球_法属圭亚那",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GY",
 | 
						||
			Name: "全球_圭亚那",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PE",
 | 
						||
			Name: "全球_秘鲁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "PY",
 | 
						||
			Name: "全球_巴拉圭",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SR",
 | 
						||
			Name: "全球_苏里南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "UY",
 | 
						||
			Name: "全球_乌拉圭",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "VE",
 | 
						||
			Name: "全球_委内瑞拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MF",
 | 
						||
			Name: "全球_法属圣马丁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SX",
 | 
						||
			Name: "全球_荷属圣马丁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AF",
 | 
						||
			Name: "全球_非洲",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AO",
 | 
						||
			Name: "全球_安哥拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BF",
 | 
						||
			Name: "全球_布基纳法索",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BI",
 | 
						||
			Name: "全球_布隆迪",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BJ",
 | 
						||
			Name: "全球_贝宁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "BW",
 | 
						||
			Name: "全球_博茨瓦纳",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CD",
 | 
						||
			Name: "全球_刚果金",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CF",
 | 
						||
			Name: "全球_中非",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CG",
 | 
						||
			Name: "全球_刚果布",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CI",
 | 
						||
			Name: "全球_科特迪瓦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CM",
 | 
						||
			Name: "全球_喀麦隆",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "CV",
 | 
						||
			Name: "全球_佛得角",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DJ",
 | 
						||
			Name: "全球_吉布提",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "DZ",
 | 
						||
			Name: "全球_阿尔及利亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "EG",
 | 
						||
			Name: "全球_埃及",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "EH",
 | 
						||
			Name: "全球_西撒哈拉",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ER",
 | 
						||
			Name: "全球_厄立特里亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ET",
 | 
						||
			Name: "全球_埃塞俄比亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GA",
 | 
						||
			Name: "全球_加蓬",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GH",
 | 
						||
			Name: "全球_加纳",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GM",
 | 
						||
			Name: "全球_冈比亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GN",
 | 
						||
			Name: "全球_几内亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GQ",
 | 
						||
			Name: "全球_赤道几内亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "GW",
 | 
						||
			Name: "全球_几内亚比绍",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KE",
 | 
						||
			Name: "全球_肯尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "KM",
 | 
						||
			Name: "全球_科摩罗",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LR",
 | 
						||
			Name: "全球_利比里亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LS",
 | 
						||
			Name: "全球_莱索托",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "LY",
 | 
						||
			Name: "全球_利比亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MA",
 | 
						||
			Name: "全球_摩洛哥",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MG",
 | 
						||
			Name: "全球_马达加斯加",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ML",
 | 
						||
			Name: "全球_马里",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MR",
 | 
						||
			Name: "全球_毛里塔尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MU",
 | 
						||
			Name: "全球_毛里求斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MW",
 | 
						||
			Name: "全球_马拉维",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "MZ",
 | 
						||
			Name: "全球_莫桑比克",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NE",
 | 
						||
			Name: "全球_尼日尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "NG",
 | 
						||
			Name: "全球_尼日利亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "RE",
 | 
						||
			Name: "全球_留尼汪",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "RW",
 | 
						||
			Name: "全球_卢旺达",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SC",
 | 
						||
			Name: "全球_塞舌尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SL",
 | 
						||
			Name: "全球_塞拉利昂",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SN",
 | 
						||
			Name: "全球_塞内加尔",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SO",
 | 
						||
			Name: "全球_索马里",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SS",
 | 
						||
			Name: "全球_南苏丹",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ST",
 | 
						||
			Name: "全球_圣多美和普林西比",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "SZ",
 | 
						||
			Name: "全球_斯威士兰",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TD",
 | 
						||
			Name: "全球_乍得",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TG",
 | 
						||
			Name: "全球_多哥",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TN",
 | 
						||
			Name: "全球_突尼斯",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "TZ",
 | 
						||
			Name: "全球_坦桑尼亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "UG",
 | 
						||
			Name: "全球_乌干达",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "YT",
 | 
						||
			Name: "全球_马约特",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ZA",
 | 
						||
			Name: "全球_南非",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ZM",
 | 
						||
			Name: "全球_赞比亚",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "ZW",
 | 
						||
			Name: "全球_津巴布韦",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "AQ",
 | 
						||
			Name: "全球_南极洲",
 | 
						||
		},
 | 
						||
	}...)
 | 
						||
 | 
						||
	// 地域线路
 | 
						||
	routes = append(routes, []*dnstypes.Route{
 | 
						||
		{
 | 
						||
			Code: "Beijing",
 | 
						||
			Name: "中国_北京",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Hebei",
 | 
						||
			Name: "中国_河北",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Tianjin",
 | 
						||
			Name: "中国_天津",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Shanxi",
 | 
						||
			Name: "中国_山西",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Neimenggu",
 | 
						||
			Name: "中国_内蒙古",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Heilongjiang",
 | 
						||
			Name: "中国_黑龙江",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Jilin",
 | 
						||
			Name: "中国_吉林",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Liaoning",
 | 
						||
			Name: "中国_辽宁",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Jiangsu",
 | 
						||
			Name: "中国_江苏",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Shanghai",
 | 
						||
			Name: "中国_上海",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Zhejiang",
 | 
						||
			Name: "中国_浙江",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Anhui",
 | 
						||
			Name: "中国_安徽",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Fujian",
 | 
						||
			Name: "中国_福建",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Jiangxi",
 | 
						||
			Name: "中国_江西",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Shandong",
 | 
						||
			Name: "中国_山东",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Hubei",
 | 
						||
			Name: "中国_湖北",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Hunan",
 | 
						||
			Name: "中国_湖南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Henan",
 | 
						||
			Name: "中国_河南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Guangdong",
 | 
						||
			Name: "中国_广东",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Guangxi",
 | 
						||
			Name: "中国_广西",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Hainan",
 | 
						||
			Name: "中国_海南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Sichuan",
 | 
						||
			Name: "中国_四川",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Xizang",
 | 
						||
			Name: "中国_西藏",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Chongqing",
 | 
						||
			Name: "中国_重庆",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Yunnan",
 | 
						||
			Name: "中国_云南",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Guizhou",
 | 
						||
			Name: "中国_贵州",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Gansu",
 | 
						||
			Name: "中国_甘肃",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Xinjiang",
 | 
						||
			Name: "中国_新疆",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Shaanxi",
 | 
						||
			Name: "中国_陕西",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Qinghai",
 | 
						||
			Name: "中国_青海",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Ningxia",
 | 
						||
			Name: "中国_宁夏",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Huabei",
 | 
						||
			Name: "中国_华北地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Dongbei",
 | 
						||
			Name: "中国_东北地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Huadong",
 | 
						||
			Name: "中国_华东地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Huazhong",
 | 
						||
			Name: "中国_华中地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Huanan",
 | 
						||
			Name: "中国_华南地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Xinan",
 | 
						||
			Name: "中国_西南地区",
 | 
						||
		},
 | 
						||
		{
 | 
						||
			Code: "Xibei",
 | 
						||
			Name: "中国_西北地区",
 | 
						||
		},
 | 
						||
	}...)
 | 
						||
 | 
						||
	return
 | 
						||
}
 | 
						||
 | 
						||
// QueryRecord 查询单个记录
 | 
						||
func (this *HuaweiDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
 | 
						||
	var resp = new(huaweidns.RecordSetsResponse)
 | 
						||
	err := this.doAPI(http.MethodGet, "/v2.1/recordsets", map[string]string{
 | 
						||
		"name": name + "." + domain + ".",
 | 
						||
		"type": recordType,
 | 
						||
	}, maps.Map{}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	if len(resp.RecordSets) == 0 {
 | 
						||
		return nil, nil
 | 
						||
	}
 | 
						||
 | 
						||
	var recordSet = resp.RecordSets[0]
 | 
						||
	if len(recordSet.Records) == 0 {
 | 
						||
		return nil, nil
 | 
						||
	}
 | 
						||
 | 
						||
	return &dnstypes.Record{
 | 
						||
		Id:    recordSet.Id + "@" + recordSet.Records[0],
 | 
						||
		Name:  name,
 | 
						||
		Type:  recordType,
 | 
						||
		Value: recordSet.Records[0],
 | 
						||
		Route: recordSet.Line,
 | 
						||
		TTL:   types.Int32(recordSet.Ttl),
 | 
						||
	}, nil
 | 
						||
}
 | 
						||
 | 
						||
// QueryRecords 查询多个记录
 | 
						||
func (this *HuaweiDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
 | 
						||
	var resp = new(huaweidns.RecordSetsResponse)
 | 
						||
	err := this.doAPI(http.MethodGet, "/v2.1/recordsets", map[string]string{
 | 
						||
		"name": name + "." + domain + ".",
 | 
						||
		"type": recordType,
 | 
						||
	}, maps.Map{}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	if len(resp.RecordSets) == 0 {
 | 
						||
		return nil, nil
 | 
						||
	}
 | 
						||
 | 
						||
	var result = []*dnstypes.Record{}
 | 
						||
	for _, recordSet := range resp.RecordSets {
 | 
						||
		if len(recordSet.Records) == 0 {
 | 
						||
			continue
 | 
						||
		}
 | 
						||
 | 
						||
		for _, record := range recordSet.Records {
 | 
						||
			result = append(result, &dnstypes.Record{
 | 
						||
				Id:    recordSet.Id + "@" + record,
 | 
						||
				Name:  name,
 | 
						||
				Type:  recordType,
 | 
						||
				Value: record,
 | 
						||
				Route: recordSet.Line,
 | 
						||
				TTL:   types.Int32(recordSet.Ttl),
 | 
						||
			})
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return result, nil
 | 
						||
}
 | 
						||
 | 
						||
// AddRecord 设置记录
 | 
						||
func (this *HuaweiDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
 | 
						||
	zoneId, err := this.findZoneIdWithDomain(domain)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, newRecord)
 | 
						||
	}
 | 
						||
 | 
						||
	var resp = new(huaweidns.ZonesCreateRecordSetResponse)
 | 
						||
	var ttl = newRecord.TTL
 | 
						||
	if ttl <= 0 {
 | 
						||
		ttl = 300
 | 
						||
	}
 | 
						||
 | 
						||
	// 华为云TXT需要加引号
 | 
						||
	if newRecord.Type == dnstypes.RecordTypeTXT {
 | 
						||
		newRecord.Value = "\"" + strings.Trim(newRecord.Value, "\"") + "\""
 | 
						||
	}
 | 
						||
 | 
						||
	err = this.doAPI(http.MethodPost, "/v2.1/zones/"+zoneId+"/recordsets", map[string]string{}, maps.Map{
 | 
						||
		"name":        newRecord.Name + "." + domain + ".",
 | 
						||
		"description": "CDN系统自动创建",
 | 
						||
		"type":        newRecord.Type,
 | 
						||
		"records":     []string{newRecord.Value},
 | 
						||
		"line":        newRecord.Route,
 | 
						||
		"ttl":         ttl,
 | 
						||
	}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, newRecord)
 | 
						||
	}
 | 
						||
 | 
						||
	newRecord.Id = resp.Id + "@" + newRecord.Value
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// UpdateRecord 修改记录
 | 
						||
func (this *HuaweiDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
 | 
						||
	zoneId, err := this.findZoneIdWithDomain(domain)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, newRecord)
 | 
						||
	}
 | 
						||
 | 
						||
	var recordId string
 | 
						||
	var atIndex = strings.Index(record.Id, "@")
 | 
						||
	if atIndex > 0 {
 | 
						||
		recordId = record.Id[:atIndex]
 | 
						||
	} else {
 | 
						||
		recordId = record.Id
 | 
						||
	}
 | 
						||
 | 
						||
	var ttl = newRecord.TTL
 | 
						||
	if ttl <= 0 {
 | 
						||
		ttl = 300
 | 
						||
	}
 | 
						||
 | 
						||
	// 华为云TXT需要加引号
 | 
						||
	if newRecord.Type == dnstypes.RecordTypeTXT {
 | 
						||
		newRecord.Value = "\"" + strings.Trim(newRecord.Value, "\"") + "\""
 | 
						||
	}
 | 
						||
 | 
						||
	var resp = new(huaweidns.ZonesUpdateRecordSetResponse)
 | 
						||
	err = this.doAPI(http.MethodPut, "/v2.1/zones/"+zoneId+"/recordsets/"+recordId, map[string]string{}, maps.Map{
 | 
						||
		"name":        newRecord.Name + "." + domain + ".",
 | 
						||
		"description": "CDN系统自动创建",
 | 
						||
		"type":        newRecord.Type,
 | 
						||
		"records":     []string{newRecord.Value},
 | 
						||
		"line":        newRecord.Route, // TODO 华为云此API无法修改线路,API地址:https://support.huaweicloud.com/api-dns/dns_api_65006.html
 | 
						||
		"ttl":         ttl,
 | 
						||
	}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, newRecord)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// DeleteRecord 删除记录
 | 
						||
func (this *HuaweiDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
 | 
						||
	zoneId, err := this.findZoneIdWithDomain(domain)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, record)
 | 
						||
	}
 | 
						||
 | 
						||
	var recordId string
 | 
						||
	var atIndex = strings.Index(record.Id, "@")
 | 
						||
	if atIndex > 0 {
 | 
						||
		recordId = record.Id[:atIndex]
 | 
						||
	} else {
 | 
						||
		recordId = record.Id
 | 
						||
	}
 | 
						||
 | 
						||
	var resp = new(huaweidns.ZonesDeleteRecordSetResponse)
 | 
						||
	err = this.doAPI(http.MethodDelete, "/v2.1/zones/"+zoneId+"/recordsets/"+recordId, map[string]string{}, maps.Map{}, resp)
 | 
						||
	if err != nil {
 | 
						||
		return this.WrapError(err, domain, record)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// DefaultRoute 默认线路
 | 
						||
func (this *HuaweiDNSProvider) DefaultRoute() string {
 | 
						||
	return "default_view"
 | 
						||
}
 | 
						||
 | 
						||
func (this *HuaweiDNSProvider) doAPI(method string, apiPath string, args map[string]string, bodyMap maps.Map, respPtr interface{}) error {
 | 
						||
	var endpoint = HuaweiDNSDefaultEndpoint
 | 
						||
	if len(this.endpoint) > 0 {
 | 
						||
		// 是否直接为区域
 | 
						||
		if this.endpointRegionReg.MatchString(this.endpoint) {
 | 
						||
			switch this.endpoint {
 | 
						||
			case "All", "all":
 | 
						||
				endpoint = "https://dns.myhuaweicloud.com/"
 | 
						||
			default:
 | 
						||
				endpoint = "https://dns." + this.endpoint + ".myhuaweicloud.com/"
 | 
						||
			}
 | 
						||
		} else if this.endpointDomainReg.MatchString(this.endpoint) { // 是否直接为域名
 | 
						||
			endpoint = "https://" + this.endpoint + "/"
 | 
						||
		} else {
 | 
						||
			// 是否为URL
 | 
						||
			_, err := url.Parse(this.endpoint)
 | 
						||
			if err != nil {
 | 
						||
				return errors.New("invalid endpoint '" + this.endpoint + "'")
 | 
						||
			}
 | 
						||
			endpoint = this.endpoint
 | 
						||
			if !strings.HasSuffix(endpoint, "/") {
 | 
						||
				endpoint += "/"
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	var apiURL = endpoint + strings.TrimLeft(apiPath, "/")
 | 
						||
	u, err := url.Parse(endpoint)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	var apiHost = u.Host
 | 
						||
	var argStrings = []string{}
 | 
						||
	if len(args) > 0 {
 | 
						||
		apiURL += "?"
 | 
						||
		for k, v := range args {
 | 
						||
			argStrings = append(argStrings, k+"="+url.QueryEscape(v))
 | 
						||
		}
 | 
						||
		apiURL += strings.Join(argStrings, "&")
 | 
						||
	}
 | 
						||
	sort.Strings(argStrings)
 | 
						||
	method = strings.ToUpper(method)
 | 
						||
 | 
						||
	var bodyReader io.Reader = nil
 | 
						||
	var bodyData []byte
 | 
						||
	if bodyMap != nil {
 | 
						||
		bodyData, err = json.Marshal(bodyMap)
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
		bodyReader = bytes.NewReader(bodyData)
 | 
						||
	}
 | 
						||
 | 
						||
	req, err := http.NewRequest(method, apiURL, bodyReader)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
 | 
						||
	var contentType = "application/json"
 | 
						||
	var host = apiHost
 | 
						||
	var datetime = time.Now().UTC().Format("20060102T150405Z")
 | 
						||
	if !strings.HasSuffix(apiPath, "/") {
 | 
						||
		apiPath += "/"
 | 
						||
	}
 | 
						||
	var canonicalRequest = method + "\n" + apiPath + "\n" + strings.Join(argStrings, "&") + "\ncontent-type:" + contentType + "\nhost:" + host + "\nx-sdk-date:" + datetime + "\n" + "\ncontent-type;host;x-sdk-date"
 | 
						||
 | 
						||
	var h = sha256.New()
 | 
						||
	_, err = h.Write(bodyData)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	canonicalRequest += "\n" + fmt.Sprintf("%x", h.Sum(nil))
 | 
						||
 | 
						||
	var h2 = sha256.New()
 | 
						||
	_, err = h2.Write([]byte(canonicalRequest))
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	var source = "SDK-HMAC-SHA256\n" + datetime + "\n" + fmt.Sprintf("%x", h2.Sum(nil))
 | 
						||
	var h3 = hmac.New(sha256.New, []byte(this.accessKeySecret))
 | 
						||
	h3.Write([]byte(source))
 | 
						||
	signString := fmt.Sprintf("%x", h3.Sum(nil))
 | 
						||
	req.Header.Set("Host", host)
 | 
						||
	req.Header.Set("Content-Type", contentType)
 | 
						||
	req.Header.Set("x-sdk-date", datetime)
 | 
						||
	req.Header.Set("Authorization", "SDK-HMAC-SHA256 Access="+this.accessKeyId+", SignedHeaders=content-type;host;x-sdk-date, Signature="+signString)
 | 
						||
 | 
						||
	resp, err := huaweiDNSHTTPClient.Do(req)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	defer func() {
 | 
						||
		_ = resp.Body.Close()
 | 
						||
	}()
 | 
						||
 | 
						||
	data, err := io.ReadAll(resp.Body)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
 | 
						||
	if resp.StatusCode == 0 {
 | 
						||
		return errors.New("invalid response status '" + strconv.Itoa(resp.StatusCode) + "', response '" + string(data) + "'")
 | 
						||
	}
 | 
						||
 | 
						||
	err = json.Unmarshal(data, respPtr)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
 | 
						||
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
 | 
						||
		return errors.New("response error: status code: " + types.String(resp.StatusCode) + ", response data: " + string(data))
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
func (this *HuaweiDNSProvider) findZoneIdWithDomain(domain string) (string, error) {
 | 
						||
	var resp = new(huaweidns.ZonesResponse)
 | 
						||
	err := this.doAPI(http.MethodGet, "/v2/zones", map[string]string{"name": domain}, nil, resp)
 | 
						||
	if err != nil {
 | 
						||
		return "", err
 | 
						||
	}
 | 
						||
 | 
						||
	for _, zone := range resp.Zones {
 | 
						||
		if zone.Name == domain+"." {
 | 
						||
			return zone.Id, nil
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return "", errors.New("can not find zone id for '" + domain + "'")
 | 
						||
}
 |