mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	域名解析增加EdgeDNS API
This commit is contained in:
		
							
								
								
									
										441
									
								
								internal/dnsclients/provider_edge_dns_api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										441
									
								
								internal/dnsclients/provider_edge_dns_api.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,441 @@
 | 
				
			|||||||
 | 
					// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dnsclients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto/tls"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/edgeapi"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var edgeDNSHTTPClient = &http.Client{
 | 
				
			||||||
 | 
						Timeout: 10 * time.Second,
 | 
				
			||||||
 | 
						Transport: &http.Transport{
 | 
				
			||||||
 | 
							TLSClientConfig: &tls.Config{
 | 
				
			||||||
 | 
								InsecureSkipVerify: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EdgeDNSAPIProvider struct {
 | 
				
			||||||
 | 
						host            string
 | 
				
			||||||
 | 
						accessKeyId     string
 | 
				
			||||||
 | 
						accessKeySecret string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						role                 string // admin | user
 | 
				
			||||||
 | 
						accessToken          string
 | 
				
			||||||
 | 
						accessTokenExpiresAt int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Auth 认证
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) Auth(params maps.Map) error {
 | 
				
			||||||
 | 
						this.role = params.GetString("role")
 | 
				
			||||||
 | 
						this.host = params.GetString("host")
 | 
				
			||||||
 | 
						this.accessKeyId = params.GetString("accessKeyId")
 | 
				
			||||||
 | 
						this.accessKeySecret = params.GetString("accessKeySecret")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.role) == 0 {
 | 
				
			||||||
 | 
							this.role = "user"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.host) == 0 {
 | 
				
			||||||
 | 
							return errors.New("'host' should not be empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !regexp.MustCompile(`^(?i)(http|https):`).MatchString(this.host) {
 | 
				
			||||||
 | 
							this.host = "http://" + this.host
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetDomains 获取所有域名列表
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) GetDomains() (domains []string, err error) {
 | 
				
			||||||
 | 
						var offset = 0
 | 
				
			||||||
 | 
						var size = 100
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							var resp = &edgeapi.ListNSDomainsResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSDomainService/ListNSDomains", map[string]any{
 | 
				
			||||||
 | 
								"offset": offset,
 | 
				
			||||||
 | 
								"size":   size,
 | 
				
			||||||
 | 
							}, resp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, domain := range resp.Data.NSDomains {
 | 
				
			||||||
 | 
								domains = append(domains, domain.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(resp.Data.NSDomains) < size {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							offset += size
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetRecords 获取域名解析记录列表
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
 | 
				
			||||||
 | 
						var domainResp = &edgeapi.FindDomainWithNameResponse{}
 | 
				
			||||||
 | 
						err = this.doAPI("/NSDomainService/FindNSDomainWithName", map[string]any{
 | 
				
			||||||
 | 
							"name": domain,
 | 
				
			||||||
 | 
						}, domainResp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var domainId = domainResp.Data.NSDomain.Id
 | 
				
			||||||
 | 
						if domainId == 0 {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var offset = 0
 | 
				
			||||||
 | 
						var size = 100
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							var recordsResp = &edgeapi.ListNSRecordsResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSRecordService/ListNSRecords", map[string]any{
 | 
				
			||||||
 | 
								"nsDomainId": domainId,
 | 
				
			||||||
 | 
								"offset":     offset,
 | 
				
			||||||
 | 
								"size":       size,
 | 
				
			||||||
 | 
							}, recordsResp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var nsRecords = recordsResp.Data.NSRecords
 | 
				
			||||||
 | 
							for _, record := range nsRecords {
 | 
				
			||||||
 | 
								var routeCode = this.DefaultRoute()
 | 
				
			||||||
 | 
								if len(record.NSRoutes) > 0 {
 | 
				
			||||||
 | 
									routeCode = record.NSRoutes[0].Code
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								records = append(records, &dnstypes.Record{
 | 
				
			||||||
 | 
									Id:    types.String(record.Id),
 | 
				
			||||||
 | 
									Name:  record.Name,
 | 
				
			||||||
 | 
									Type:  record.Type,
 | 
				
			||||||
 | 
									Value: record.Value,
 | 
				
			||||||
 | 
									Route: routeCode,
 | 
				
			||||||
 | 
									TTL:   record.TTL,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(nsRecords) < size {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							offset += size
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetRoutes 读取域名支持的线路数据
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
 | 
				
			||||||
 | 
						// default
 | 
				
			||||||
 | 
						routes = append(routes, &dnstypes.Route{
 | 
				
			||||||
 | 
							Name: "默认线路",
 | 
				
			||||||
 | 
							Code: this.DefaultRoute(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 世界区域
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var routesResp = &edgeapi.FindAllNSRoutesResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSRouteService/FindAllDefaultWorldRegionRoutes", map[string]any{}, routesResp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, route := range routesResp.Data.NSRoutes {
 | 
				
			||||||
 | 
								routes = append(routes, &dnstypes.Route{
 | 
				
			||||||
 | 
									Name: route.Name,
 | 
				
			||||||
 | 
									Code: route.Code,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 中国省份
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var routesResp = &edgeapi.FindAllNSRoutesResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSRouteService/FindAllDefaultChinaProvinceRoutes", map[string]any{}, routesResp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, route := range routesResp.Data.NSRoutes {
 | 
				
			||||||
 | 
								routes = append(routes, &dnstypes.Route{
 | 
				
			||||||
 | 
									Name: route.Name,
 | 
				
			||||||
 | 
									Code: route.Code,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ISP
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var routesResp = &edgeapi.FindAllNSRoutesResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSRouteService/FindAllDefaultISPRoutes", map[string]any{}, routesResp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, route := range routesResp.Data.NSRoutes {
 | 
				
			||||||
 | 
								routes = append(routes, &dnstypes.Route{
 | 
				
			||||||
 | 
									Name: route.Name,
 | 
				
			||||||
 | 
									Code: route.Code,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 自定义
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var routesResp = &edgeapi.FindAllNSRoutesResponse{}
 | 
				
			||||||
 | 
							err = this.doAPI("/NSRouteService/FindAllNSRoutes", map[string]any{}, routesResp)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, route := range routesResp.Data.NSRoutes {
 | 
				
			||||||
 | 
								routes = append(routes, &dnstypes.Route{
 | 
				
			||||||
 | 
									Name: route.Name,
 | 
				
			||||||
 | 
									Code: route.Code,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryRecord 查询单个记录
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
 | 
				
			||||||
 | 
						var domainResp = &edgeapi.FindDomainWithNameResponse{}
 | 
				
			||||||
 | 
						err := this.doAPI("/NSDomainService/FindNSDomainWithName", map[string]any{
 | 
				
			||||||
 | 
							"name": domain,
 | 
				
			||||||
 | 
						}, domainResp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var domainId = domainResp.Data.NSDomain.Id
 | 
				
			||||||
 | 
						if domainId == 0 {
 | 
				
			||||||
 | 
							return nil, errors.New("can not find domain '" + domain + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var recordResp = &edgeapi.FindNSRecordWithNameAndTypeResponse{}
 | 
				
			||||||
 | 
						err = this.doAPI("/NSRecordService/FindNSRecordWithNameAndType", map[string]any{
 | 
				
			||||||
 | 
							"nsDomainId": domainId,
 | 
				
			||||||
 | 
							"name":       name,
 | 
				
			||||||
 | 
							"type":       recordType,
 | 
				
			||||||
 | 
						}, recordResp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var record = recordResp.Data.NSRecord
 | 
				
			||||||
 | 
						if record.Id <= 0 {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var routeCode = this.DefaultRoute()
 | 
				
			||||||
 | 
						if len(record.NSRoutes) > 0 {
 | 
				
			||||||
 | 
							routeCode = record.NSRoutes[0].Code
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &dnstypes.Record{
 | 
				
			||||||
 | 
							Id:    types.String(record.Id),
 | 
				
			||||||
 | 
							Name:  record.Name,
 | 
				
			||||||
 | 
							Type:  record.Type,
 | 
				
			||||||
 | 
							Value: record.Value,
 | 
				
			||||||
 | 
							Route: routeCode,
 | 
				
			||||||
 | 
							TTL:   record.TTL,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddRecord 设置记录
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
 | 
				
			||||||
 | 
						var domainResp = &edgeapi.FindDomainWithNameResponse{}
 | 
				
			||||||
 | 
						err := this.doAPI("/NSDomainService/FindNSDomainWithName", map[string]any{
 | 
				
			||||||
 | 
							"name": domain,
 | 
				
			||||||
 | 
						}, domainResp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var domainId = domainResp.Data.NSDomain.Id
 | 
				
			||||||
 | 
						if domainId == 0 {
 | 
				
			||||||
 | 
							return errors.New("can not find domain '" + domain + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
 | 
				
			||||||
 | 
							newRecord.Value += "."
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var createResp = &edgeapi.CreateNSRecordResponse{}
 | 
				
			||||||
 | 
						var routes = []string{}
 | 
				
			||||||
 | 
						if len(newRecord.Route) > 0 {
 | 
				
			||||||
 | 
							routes = []string{newRecord.Route}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = this.doAPI("/NSRecordService/CreateNSRecord", map[string]any{
 | 
				
			||||||
 | 
							"nsDomainId":   domainId,
 | 
				
			||||||
 | 
							"name":         newRecord.Name,
 | 
				
			||||||
 | 
							"type":         strings.ToUpper(newRecord.Type),
 | 
				
			||||||
 | 
							"value":        newRecord.Value,
 | 
				
			||||||
 | 
							"ttl":          newRecord.TTL,
 | 
				
			||||||
 | 
							"nsRouteCodes": routes,
 | 
				
			||||||
 | 
						}, createResp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newRecord.Id = types.String(createResp.Data.NSRecordId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateRecord 修改记录
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
 | 
				
			||||||
 | 
						if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
 | 
				
			||||||
 | 
							newRecord.Value += "."
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var createResp = &edgeapi.UpdateNSRecordResponse{}
 | 
				
			||||||
 | 
						var routes = []string{}
 | 
				
			||||||
 | 
						if len(newRecord.Route) > 0 {
 | 
				
			||||||
 | 
							routes = []string{newRecord.Route}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := this.doAPI("/NSRecordService/UpdateNSRecord", map[string]any{
 | 
				
			||||||
 | 
							"nsRecordId":   types.Int64(record.Id),
 | 
				
			||||||
 | 
							"name":         newRecord.Name,
 | 
				
			||||||
 | 
							"type":         strings.ToUpper(newRecord.Type),
 | 
				
			||||||
 | 
							"value":        newRecord.Value,
 | 
				
			||||||
 | 
							"ttl":          newRecord.TTL,
 | 
				
			||||||
 | 
							"nsRouteCodes": routes,
 | 
				
			||||||
 | 
							"isOn":         true, // important
 | 
				
			||||||
 | 
						}, createResp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteRecord 删除记录
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
 | 
				
			||||||
 | 
						var resp = &edgeapi.SuccessResponse{}
 | 
				
			||||||
 | 
						err := this.doAPI("/NSRecordService/DeleteNSRecord", map[string]any{
 | 
				
			||||||
 | 
							"nsRecordId": types.Int64(record.Id),
 | 
				
			||||||
 | 
						}, resp)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultRoute 默认线路
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) DefaultRoute() string {
 | 
				
			||||||
 | 
						return "default"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) doAPI(path string, params map[string]any, respPtr edgeapi.ResponseInterface) error {
 | 
				
			||||||
 | 
						accessToken, err := this.getToken()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						paramsJSON, err := json.Marshal(params)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						req, err := http.NewRequest(http.MethodPost, this.host+path, bytes.NewReader(paramsJSON))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
 | 
				
			||||||
 | 
						req.Header.Set("X-Edge-Access-Token", accessToken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := edgeDNSHTTPClient.Do(req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return errors.New("invalid response status code '" + types.String(resp.StatusCode) + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data, err := io.ReadAll(resp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(data, respPtr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.New("decode response failed: " + err.Error() + ", JSON: " + string(data))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !respPtr.IsValid() {
 | 
				
			||||||
 | 
							return respPtr.Error()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *EdgeDNSAPIProvider) getToken() (string, error) {
 | 
				
			||||||
 | 
						if len(this.accessToken) > 0 && this.accessTokenExpiresAt > time.Now().Unix()+600 /** 600秒是防止当前服务器和API服务器之间有时间差 **/ {
 | 
				
			||||||
 | 
							return this.accessToken, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var params = maps.Map{
 | 
				
			||||||
 | 
							"type":        this.role,
 | 
				
			||||||
 | 
							"accessKeyId": this.accessKeyId,
 | 
				
			||||||
 | 
							"accessKey":   this.accessKeySecret,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						paramsJSON, err := json.Marshal(params)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						req, err := http.NewRequest(http.MethodPost, this.host+"/APIAccessTokenService/getAPIAccessToken", bytes.NewReader(paramsJSON))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
 | 
				
			||||||
 | 
						resp, err := edgeDNSHTTPClient.Do(req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							_ = resp.Body.Close()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
 | 
							return "", errors.New("invalid response code '" + types.String(resp.StatusCode) + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data, err := io.ReadAll(resp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tokenResp = &edgeapi.GetAPIAccessToken{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(data, tokenResp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if tokenResp.Code != 200 {
 | 
				
			||||||
 | 
							return "", errors.New("invalid code '" + types.String(tokenResp.Code) + "', message: " + tokenResp.Message)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.accessToken = tokenResp.Data.Token
 | 
				
			||||||
 | 
						this.accessTokenExpiresAt = tokenResp.Data.ExpiresAt
 | 
				
			||||||
 | 
						return this.accessToken, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										163
									
								
								internal/dnsclients/provider_edge_dns_api_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								internal/dnsclients/provider_edge_dns_api_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dnsclients_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/logs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const edgeDNSAPIDomainName = "hello2.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_GetDomains(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						domains, err := provider.GetDomains()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("domains:", domains)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_GetRecords(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						records, err := provider.GetRecords(edgeDNSAPIDomainName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logs.PrintAsJSON(records, t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_GetRoutes(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						routes, err := provider.GetRoutes(edgeDNSAPIDomainName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logs.PrintAsJSON(routes, t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_QueryRecord(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						record, err := provider.QueryRecord(edgeDNSAPIDomainName, "cdn", dnstypes.RecordTypeA)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logs.PrintAsJSON(record)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_AddRecord(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = provider.AddRecord(edgeDNSAPIDomainName, &dnstypes.Record{
 | 
				
			||||||
 | 
							Id:    "",
 | 
				
			||||||
 | 
							Name:  "example",
 | 
				
			||||||
 | 
							Type:  dnstypes.RecordTypeA,
 | 
				
			||||||
 | 
							Value: "10.0.0.1",
 | 
				
			||||||
 | 
							Route: "china:province:beijing",
 | 
				
			||||||
 | 
							TTL:   300,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_UpdateRecord(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						record, err := provider.QueryRecord(edgeDNSAPIDomainName, "cdn", dnstypes.RecordTypeA)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if record == nil {
 | 
				
			||||||
 | 
							t.Log("not found record")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//record.Id = ""
 | 
				
			||||||
 | 
						err = provider.UpdateRecord(edgeDNSAPIDomainName, record, &dnstypes.Record{
 | 
				
			||||||
 | 
							Id:    "",
 | 
				
			||||||
 | 
							Name:  record.Name,
 | 
				
			||||||
 | 
							Type:  record.Type,
 | 
				
			||||||
 | 
							Value: "127.0.0.3",
 | 
				
			||||||
 | 
							Route: record.Route,
 | 
				
			||||||
 | 
							TTL:   30,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_DeleteRecord(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						record, err := provider.QueryRecord(edgeDNSAPIDomainName, "example", "A")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if record == nil {
 | 
				
			||||||
 | 
							t.Log("not found")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = provider.DeleteRecord(edgeDNSAPIDomainName, &dnstypes.Record{
 | 
				
			||||||
 | 
							Id:    record.Id,
 | 
				
			||||||
 | 
							Name:  "example",
 | 
				
			||||||
 | 
							Type:  "A",
 | 
				
			||||||
 | 
							Value: "",
 | 
				
			||||||
 | 
							Route: "",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEdgeDNSAPIProvider_DefaultRoute(t *testing.T) {
 | 
				
			||||||
 | 
						provider, err := testEdgeDNSAPIProvider()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Log(provider.DefaultRoute())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testEdgeDNSAPIProvider() (dnsclients.ProviderInterface, error) {
 | 
				
			||||||
 | 
						provider := &dnsclients.EdgeDNSAPIProvider{}
 | 
				
			||||||
 | 
						err := provider.Auth(maps.Map{
 | 
				
			||||||
 | 
							"role":            "user",
 | 
				
			||||||
 | 
							"host":            "http://127.0.0.1:8004",
 | 
				
			||||||
 | 
							"accessKeyId":     "JOvsyXIFqkQbh5kl",
 | 
				
			||||||
 | 
							"accessKeySecret": "t0RY8YO3R58VbJJNp0RqKw9KWNpObwtE",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return provider, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,65 +0,0 @@
 | 
				
			|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package dnsclients
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
 | 
					 | 
				
			||||||
	"github.com/iwind/TeaGo/maps"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UserEdgeDNSProvider struct {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Auth 认证
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) Auth(params maps.Map) error {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetDomains 获取所有域名列表
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) GetDomains() (domains []string, err error) {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetRecords 获取域名解析记录列表
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetRoutes 读取域名支持的线路数据
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// QueryRecord 查询单个记录
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return nil, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// AddRecord 设置记录
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UpdateRecord 修改记录
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DeleteRecord 删除记录
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DefaultRoute 默认线路
 | 
					 | 
				
			||||||
func (this *UserEdgeDNSProvider) DefaultRoute() string {
 | 
					 | 
				
			||||||
	// TODO
 | 
					 | 
				
			||||||
	return ""
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -13,13 +13,13 @@ const (
 | 
				
			|||||||
	ProviderTypeHuaweiDNS    ProviderType = "huaweiDNS"    // 华为DNS
 | 
						ProviderTypeHuaweiDNS    ProviderType = "huaweiDNS"    // 华为DNS
 | 
				
			||||||
	ProviderTypeCloudFlare   ProviderType = "cloudFlare"   // CloudFlare DNS
 | 
						ProviderTypeCloudFlare   ProviderType = "cloudFlare"   // CloudFlare DNS
 | 
				
			||||||
	ProviderTypeLocalEdgeDNS ProviderType = "localEdgeDNS" // 和当前系统集成的EdgeDNS
 | 
						ProviderTypeLocalEdgeDNS ProviderType = "localEdgeDNS" // 和当前系统集成的EdgeDNS
 | 
				
			||||||
	ProviderTypeUserEdgeDNS  ProviderType = "userEdgeDNS"  // 通过API连接的EdgeDNS
 | 
						ProviderTypeEdgeDNSAPI   ProviderType = "edgeDNSAPI"   // 通过API连接的EdgeDNS
 | 
				
			||||||
	ProviderTypeCustomHTTP   ProviderType = "customHTTP"   // 自定义HTTP接口
 | 
						ProviderTypeCustomHTTP   ProviderType = "customHTTP"   // 自定义HTTP接口
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllProviderTypes 所有的服务商类型
 | 
					// FindAllProviderTypes 所有的服务商类型
 | 
				
			||||||
func FindAllProviderTypes() []maps.Map {
 | 
					func FindAllProviderTypes() []maps.Map {
 | 
				
			||||||
	typeMaps := []maps.Map{
 | 
						var typeMaps = []maps.Map{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"name":        "阿里云DNS",
 | 
								"name":        "阿里云DNS",
 | 
				
			||||||
			"code":        ProviderTypeAliDNS,
 | 
								"code":        ProviderTypeAliDNS,
 | 
				
			||||||
@@ -40,6 +40,11 @@ func FindAllProviderTypes() []maps.Map {
 | 
				
			|||||||
			"code":        ProviderTypeCloudFlare,
 | 
								"code":        ProviderTypeCloudFlare,
 | 
				
			||||||
			"description": "CloudFlare提供的DNS服务。",
 | 
								"description": "CloudFlare提供的DNS服务。",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"name":        "EdgeDNS API",
 | 
				
			||||||
 | 
								"code":        ProviderTypeEdgeDNSAPI,
 | 
				
			||||||
 | 
								"description": "通过API连接GoEdge商业版系统提供的DNS服务。",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typeMaps = filterTypeMaps(typeMaps)
 | 
						typeMaps = filterTypeMaps(typeMaps)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ func FindProvider(providerType ProviderType) ProviderInterface {
 | 
				
			|||||||
		return &CloudFlareProvider{}
 | 
							return &CloudFlareProvider{}
 | 
				
			||||||
	case ProviderTypeCustomHTTP:
 | 
						case ProviderTypeCustomHTTP:
 | 
				
			||||||
		return &CustomHTTPProvider{}
 | 
							return &CustomHTTPProvider{}
 | 
				
			||||||
 | 
						case ProviderTypeUserEdgeDNS:
 | 
				
			||||||
 | 
							return &EdgeDNSAPIProvider{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user