11# coding=utf-8
22"""
33ClouDNS API
4- @author: NewFuture (modifications for ClouDNS)
4+ @doc: https://www.cloudns.net/wiki/
5+ @author: NewFuture
56"""
67
78from ._base import BaseProvider , TYPE_FORM
@@ -15,12 +16,21 @@ class CloudnsProvider(BaseProvider):
1516
1617 endpoint = "https://api.cloudns.net"
1718 content_type = TYPE_FORM
19+ DEFAULT_TTL = 60 # Minimum TTL (60 seconds) for faster updates
1820
1921 def _request (self , action , ** params ):
22+ # type: (str, **(str | int | None)) -> dict | None
2023 """
2124 发送请求数据,自动添加认证参数
2225
23- Send request to ClouDNS API.
26+ Send request to ClouDNS API with authentication.
27+
28+ Args:
29+ action (str): API endpoint path
30+ params: API parameters
31+
32+ Returns:
33+ dict|None: Response data or None on error
2434 """
2535 # Add authentication
2636 params ["auth-id" ] = self .id
@@ -31,126 +41,155 @@ def _request(self, action, **params):
3141
3242 data = self ._http ("POST" , action , body = params )
3343
34- # CloudNS API returns different formats:
35- # - Success for modifications : {"status": "Success", ...}
44+ # ClouDNS API returns different formats:
45+ # - Success: {"status": "Success", ...}
3646 # - Failure: {"status": "Failed", "statusDescription": "..."}
37- # - Query success : raw data (e.g., {"id1": {...}, "id2": {...}}) without status field
47+ # - Query: raw data (e.g., {"id1": {...}, "id2": {...}}) without status field
3848
3949 # Check for explicit error status
40- if data and isinstance (data , dict ):
41- if data .get ("status" ) == "Failed" :
42- error_msg = data .get ("statusDescription" , "Unknown error" )
43- self .logger .warning ("ClouDNS API error: %s" , error_msg )
44- return None
45- # If status is "Success" or no status field (raw data), return as-is
46- return data
50+ if data and isinstance (data , dict ) and data .get ("status" ) == "Failed" :
51+ error_msg = data .get ("statusDescription" , "Unknown error" )
52+ self .logger .warning ("ClouDNS API error: %s" , error_msg )
53+ return None
4754
4855 return data
4956
5057 def _query_zone_id (self , domain ):
58+ # type: (str) -> str | None
5159 """
52- ClouDNS uses domain name directly as zone identifier
60+ 查询域名区域ID
61+
62+ Query zone ID for domain.
63+ ClouDNS uses domain name directly as zone identifier.
64+
65+ Args:
66+ domain (str): Domain name
67+
68+ Returns:
69+ str: Domain name (used as zone ID)
5370 """
5471 # ClouDNS uses domain-name directly, no numeric zone ID
55- # Return the domain itself as the zone identifier
5672 return domain
5773
5874 def _query_record (self , zone_id , subdomain , main_domain , record_type , line , extra ):
75+ # type: (str, str, str, str, str | None, dict | None) -> dict | None
5976 """
60- Query DNS records
77+ 查询DNS记录
78+
79+ Query DNS record.
6180 https://www.cloudns.net/wiki/article/57/
62- """
63- # For @ (root) records, ClouDNS uses empty string or "@"
64- host = subdomain if subdomain != "@" else ""
6581
66- params = {
67- "domain-name" : zone_id ,
68- "host" : host ,
69- "type" : record_type
70- }
82+ Args:
83+ zone_id (str): Zone ID (domain name for ClouDNS)
84+ subdomain (str): Subdomain
85+ main_domain (str): Main domain
86+ record_type (str): Record type (A, AAAA, etc.)
87+ line (str|None): Line (not used by ClouDNS)
88+ extra (dict|None): Extra parameters
89+
90+ Returns:
91+ dict|None: Record data or None if not found
92+ """
93+ # For @ (root) records, ClouDNS uses empty string
94+ host = "" if subdomain == "@" else subdomain
7195
96+ params = {"domain-name" : zone_id , "host" : host , "type" : record_type }
7297 data = self ._request ("/dns/records.json" , ** params )
7398
74- if data and isinstance (data , dict ):
75- # CloudNS returns records as a dict with record IDs as keys
76- # Format: {"id1": {record_data}, "id2": {record_data}}
77- # Or error format: {"status": "Failed", ...}
78-
79- # Check if it's an error response
80- if "status" in data :
81- return None
82-
83- # Iterate through records (values of the dict)
84- for record in data .values ():
85- # Match host - empty string means root
86- record_host = record .get ("host" , "" )
87- if (record_host == host or
88- (record_host == "@" and subdomain == "@" ) or
89- (record_host == "" and subdomain == "@" )):
90- if record .get ("type" ) == record_type :
91- return record
99+ if not data or not isinstance (data , dict ):
100+ return None
101+
102+ # Check if it's an error response (has status field)
103+ if "status" in data :
104+ return None
105+
106+ # ClouDNS returns records as dict: {"id1": {record_data}, "id2": {record_data}}
107+ # Find matching record
108+ for record in data .values ():
109+ record_host = record .get ("host" , "" )
110+ # Match host (handle both "" and "@" for root records)
111+ if record_host == host or (subdomain == "@" and record_host in ("" , "@" )):
112+ if record .get ("type" ) == record_type :
113+ return record
92114
93115 return None
94116
95117 def _create_record (self , zone_id , subdomain , main_domain , value , record_type , ttl , line , extra ):
118+ # type: (str, str, str, str, str, int | None, str | None, dict | None) -> bool
96119 """
97- Create new DNS record
120+ 创建DNS记录
121+
122+ Create new DNS record.
98123 https://www.cloudns.net/wiki/article/58/
124+
125+ Args:
126+ zone_id (str): Zone ID (domain name)
127+ subdomain (str): Subdomain
128+ main_domain (str): Main domain
129+ value (str): Record value (IP address)
130+ record_type (str): Record type (A, AAAA, etc.)
131+ ttl (int|None): TTL in seconds
132+ line (str|None): Line (not used by ClouDNS)
133+ extra (dict|None): Extra parameters
134+
135+ Returns:
136+ bool: True if successful, False otherwise
99137 """
100- # Default TTL if not specified
138+ # Use default TTL if not specified
101139 if ttl is None :
102- ttl = 3600 # 1 hour default
103-
104- # For @ (root) records
105- host = subdomain if subdomain != "@" else ""
140+ ttl = self .DEFAULT_TTL
106141
107- params = {
108- "domain-name" : zone_id ,
109- "record-type" : record_type ,
110- "host" : host ,
111- "record" : value ,
112- "ttl" : ttl
113- }
142+ # For @ (root) records, use empty string
143+ host = "" if subdomain == "@" else subdomain
114144
145+ params = {"domain-name" : zone_id , "record-type" : record_type , "host" : host , "record" : value , "ttl" : ttl }
115146 data = self ._request ("/dns/add-record.json" , ** params )
116147
117148 if data and data .get ("status" ) == "Success" :
118149 self .logger .info ("Record created successfully" )
119150 return True
120- else :
121- self .logger .error ("Failed to create record: %s" , data )
122- return False
151+
152+ self .logger .error ("Failed to create record: %s" , data )
153+ return False
123154
124155 def _update_record (self , zone_id , old_record , value , record_type , ttl , line , extra ):
156+ # type: (str, dict, str, str, int | None, str | None, dict | None) -> bool
125157 """
126- Update existing DNS record
158+ 更新DNS记录
159+
160+ Update existing DNS record.
127161 https://www.cloudns.net/wiki/article/60/
162+
163+ Args:
164+ zone_id (str): Zone ID (domain name)
165+ old_record (dict): Existing record data
166+ value (str): New record value (IP address)
167+ record_type (str): Record type (A, AAAA, etc.)
168+ ttl (int|None): TTL in seconds
169+ line (str|None): Line (not used by ClouDNS)
170+ extra (dict|None): Extra parameters
171+
172+ Returns:
173+ bool: True if successful, False otherwise
128174 """
129- # Default TTL if not specified
175+ # Use default TTL if not specified
130176 if ttl is None :
131- ttl = 3600
177+ ttl = self . DEFAULT_TTL
132178
133179 record_id = old_record .get ("id" )
134180 if not record_id :
135181 self .logger .error ("Record ID not found in old_record" )
136182 return False
137183
138- # Get original host
184+ # Get original host from record
139185 host = old_record .get ("host" , "" )
140186
141- params = {
142- "domain-name" : zone_id ,
143- "record-id" : record_id ,
144- "host" : host ,
145- "record" : value ,
146- "ttl" : ttl
147- }
148-
187+ params = {"domain-name" : zone_id , "record-id" : record_id , "host" : host , "record" : value , "ttl" : ttl }
149188 data = self ._request ("/dns/mod-record.json" , ** params )
150189
151190 if data and data .get ("status" ) == "Success" :
152191 self .logger .info ("Record updated successfully" )
153192 return True
154- else :
155- self .logger .error ("Failed to update record: %s" , data )
156- return False
193+
194+ self .logger .error ("Failed to update record: %s" , data )
195+ return False
0 commit comments