dnspod.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # coding=utf-8
  2. """
  3. DNSPOD API
  4. @doc: https://docs.dnspod.cn/api/
  5. @author: NewFuture
  6. """
  7. from ._base import BaseProvider, TYPE_FORM
  8. class DnspodProvider(BaseProvider):
  9. """
  10. DNSPOD API
  11. DNSPOD 接口解析操作库
  12. """
  13. API = "https://dnsapi.cn"
  14. content_type = TYPE_FORM
  15. DefaultLine = "默认"
  16. def _request(self, action, extra=None, **params):
  17. # type: (str, dict | None, **(str | int | bytes | bool | None)) -> dict
  18. """
  19. 发送请求数据
  20. Send request to DNSPod API.
  21. Args:
  22. action (str): API 动作/Action
  23. extra (dict|None): 额外参数/Extra params
  24. params (dict): 其它参数/Other params
  25. Returns:
  26. dict: 响应数据/Response data
  27. """
  28. # 过滤掉None参数
  29. if extra:
  30. params.update(extra)
  31. params = {k: v for k, v in params.items() if v is not None}
  32. params.update({"login_token": "{0},{1}".format(self.auth_id, self.auth_token), "format": "json"})
  33. headers = {"User-Agent": "DDNS/{0} ([email protected])".format(self.version)}
  34. data = self._http("POST", "/" + action, headers=headers, body=params)
  35. if data and data.get("status", {}).get("code") == "1": # 请求成功
  36. return data
  37. else: # 请求失败
  38. error_msg = "Unknown error"
  39. if data and isinstance(data, dict):
  40. error_msg = data.get("status", {}).get("message", "Unknown error")
  41. self.logger.warning("DNSPod API error: %s", error_msg)
  42. return data
  43. def _create_record(self, zone_id, subdomain, main_domain, value, record_type, ttl, line, extra):
  44. # type: (str, str, str, str, str, int | str | None, str | None, dict) -> bool
  45. """https://docs.dnspod.cn/api/add-record/"""
  46. res = self._request(
  47. "Record.Create",
  48. extra=extra,
  49. domain_id=zone_id,
  50. sub_domain=subdomain,
  51. value=value,
  52. record_type=record_type,
  53. record_line=line or self.DefaultLine,
  54. ttl=ttl,
  55. )
  56. record = res and res.get("record")
  57. if record: # 记录创建成功
  58. self.logger.info("Record created: %s", record)
  59. return True
  60. else: # 记录创建失败
  61. self.logger.error("Failed to create record: %s", res)
  62. return False
  63. def _update_record(self, zone_id, old_record, value, record_type, ttl, line, extra):
  64. # type: (str, dict, str, str, int | str | None, str | None, dict) -> bool
  65. """https://docs.dnspod.cn/api/modify-records/"""
  66. record_line = (line or old_record.get("line") or self.DefaultLine).replace("Default", "default")
  67. res = self._request(
  68. "Record.Modify",
  69. domain_id=zone_id,
  70. record_id=old_record.get("id"),
  71. sub_domain=old_record.get("name"),
  72. record_type=record_type,
  73. value=value,
  74. record_line=record_line,
  75. extra=extra,
  76. )
  77. record = res and res.get("record")
  78. if record: # 记录更新成功
  79. self.logger.debug("Record updated: %s", record)
  80. return True
  81. else: # 记录更新失败
  82. self.logger.error("Failed to update record: %s", res)
  83. return False
  84. def _query_zone_id(self, domain):
  85. # type: (str) -> str | None
  86. """查询域名信息 https://docs.dnspod.cn/api/domain-info/"""
  87. res = self._request("Domain.Info", domain=domain)
  88. if res and isinstance(res, dict):
  89. return res.get("domain", {}).get("id")
  90. return None
  91. def _query_record(self, zone_id, subdomain, main_domain, record_type, line, extra):
  92. # type: (str, str, str, str, str | None, dict) -> dict | None
  93. """查询记录 list 然后逐个查找 https://docs.dnspod.cn/api/record-list/"""
  94. res = self._request(
  95. "Record.List", domain_id=zone_id, sub_domain=subdomain, record_type=record_type, line=line
  96. )
  97. # length="3000"
  98. records = res.get("records", [])
  99. n = len(records)
  100. if not n:
  101. self.logger.warning("No record found for [%s] %s<%s>(line: %s)", zone_id, subdomain, record_type, line)
  102. return None
  103. if n > 1:
  104. self.logger.warning("%d records found for %s<%s>(%s):\n %s", n, subdomain, record_type, line, records)
  105. return next((r for r in records if r.get("name") == subdomain), None)
  106. return records[0]