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. endpoint = "" # CallbackProvider uses 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.id # 直接用 id 作为 url
  25. token = self.token # token 作为 POST 参数
  26. extra.update(
  27. {
  28. "__DOMAIN__": domain,
  29. "__RECORDTYPE__": record_type,
  30. "__TTL__": ttl,
  31. "__IP__": value,
  32. "__TIMESTAMP__": time(),
  33. "__LINE__": line,
  34. }
  35. )
  36. url = self._replace_vars(url, extra)
  37. method, params = "GET", None
  38. if token:
  39. # 如果有 token,使用 POST 方法
  40. method = "POST"
  41. # POST 方式,token 作为 POST 参数
  42. params = token if isinstance(token, dict) else jsondecode(token)
  43. for k, v in params.items():
  44. if hasattr(v, "replace"): # 判断是否支持字符串替换, 兼容py2,py3
  45. params[k] = self._replace_vars(v, extra)
  46. try:
  47. res = self._http(method, url, body=params)
  48. if res is not None:
  49. self.logger.info("Callback result: %s", res)
  50. return True
  51. else:
  52. self.logger.warning("Callback received empty response.")
  53. except Exception as e:
  54. self.logger.error("Callback failed: %s", e)
  55. return False
  56. def _replace_vars(self, string, mapping):
  57. # type: (str, dict) -> str
  58. """
  59. 替换字符串中的变量为实际值
  60. Replace variables in string with actual values
  61. """
  62. for k, v in mapping.items():
  63. string = string.replace(k, str(v))
  64. return string
  65. def _validate(self):
  66. # CallbackProvider uses id as URL, not as regular ID
  67. if self.endpoint or (not self.id or "://" not in self.id):
  68. # 如果 endpoint 已经设置,或者 id 不是有效的 URL,则抛出异常
  69. self.logger.critical("endpoint [%s] or id [%s] 必须是有效的URL", self.endpoint, self.id)
  70. raise ValueError("endpoint or id must be configured with URL")