callback.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # coding=utf-8
  2. """
  3. Custom Callback API
  4. 自定义回调接口解析操作库
  5. @author: 老周部落, NewFuture
  6. """
  7. from ._base import TYPE_JSON, SimpleProvider
  8. from time import time
  9. from json import loads as jsondecode
  10. class CallbackProvider(SimpleProvider):
  11. """
  12. 通用自定义回调 Provider,支持 GET/POST 任意接口。
  13. Generic custom callback provider, supports GET/POST arbitrary API.
  14. """
  15. API = "" # CallbackProvider uses auth_id as URL, no fixed API endpoint
  16. content_type = TYPE_JSON
  17. decode_response = False # Callback response is not JSON, it's a custom response
  18. def set_record(self, domain, value, record_type="A", ttl=None, line=None, **extra):
  19. """
  20. 发送自定义回调请求,支持 GET/POST
  21. Send custom callback request, support GET/POST
  22. """
  23. self.logger.info("%s => %s(%s)", domain, value, record_type)
  24. url = self.auth_id # 直接用 auth_id 作为 url
  25. token = self.auth_token # auth_token 作为 POST 参数
  26. headers = {"User-Agent": "DDNS/{0} ([email protected])".format(self.version)}
  27. extra.update(
  28. {
  29. "__DOMAIN__": domain,
  30. "__RECORDTYPE__": record_type,
  31. "__TTL__": ttl,
  32. "__IP__": value,
  33. "__TIMESTAMP__": time(),
  34. "__LINE__": line,
  35. }
  36. )
  37. url = self._replace_vars(url, extra)
  38. method, params = "GET", None
  39. if token:
  40. # 如果有 token,使用 POST 方法
  41. method = "POST"
  42. # POST 方式,token 作为 POST 参数
  43. params = token if isinstance(token, dict) else jsondecode(token)
  44. for k, v in params.items():
  45. if hasattr(v, "replace"): # 判断是否支持字符串替换, 兼容py2,py3
  46. params[k] = self._replace_vars(v, extra)
  47. try:
  48. res = self._http(method, url, body=params, headers=headers)
  49. if res is not None:
  50. self.logger.info("Callback result: %s", res)
  51. return True
  52. else:
  53. self.logger.warning("Callback received empty response.")
  54. except Exception as e:
  55. self.logger.error("Callback failed: %s", e)
  56. return False
  57. def _replace_vars(self, string, mapping):
  58. # type: (str, dict) -> str
  59. """
  60. 替换字符串中的变量为实际值
  61. Replace variables in string with actual values
  62. """
  63. for k, v in mapping.items():
  64. string = string.replace(k, str(v))
  65. return string
  66. def _validate(self):
  67. # CallbackProvider uses auth_id as URL, not as regular ID
  68. if not self.auth_id or "://" not in self.auth_id:
  69. self.logger.critical("callback ID 参数[%s] 必须是有效的URL", self.auth_id)
  70. raise ValueError("id must be configured with URL")
  71. # CallbackProvider doesn't need auth_token validation (it can be empty)