sites.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. """站点清单与地址解析。
  2. 四个线上地址共享同一个数据库和同一把 jwt 密钥,凭据完全通用;
  3. .org / .cc 是地区可达性,www / next 是代码版本(不是数据环境)。
  4. 开发机是另一个库、另一把密钥,故单独一桶,且永不作为自动 fallback 目标。
  5. """
  6. import urllib.parse
  7. from errors import WpError
  8. # bucket 决定两件事:凭据/缓存存哪一桶,以及能不能作为自动 fallback 的目标。
  9. # 只有 bucket == "online" 的四个地址共享同一个数据库与 jwt 密钥,彼此可以互替。
  10. # staging 与开发机各是**另一个库**——实测 staging 的公开 channel 数与线上不同,
  11. # 同名 channel 的 uid 也不同——所以自成一桶,且绝不参与 fallback。
  12. SITES = [
  13. {"key": "www", "url": "https://www.wikipali.org/api",
  14. "version": "稳定版", "domain": ".org", "bucket": "online"},
  15. {"key": "www.cc", "url": "https://www.wikipali.cc/api",
  16. "version": "稳定版", "domain": ".cc", "bucket": "online"},
  17. {"key": "next", "url": "https://next.wikipali.org/api",
  18. "version": "最新版", "domain": ".org", "bucket": "online"},
  19. {"key": "next.cc", "url": "https://next.wikipali.cc/api",
  20. "version": "最新版", "domain": ".cc", "bucket": "online"},
  21. {"key": "staging", "url": "https://staging.wikipali.org/api",
  22. "version": "预发布", "domain": "独立库", "bucket": "staging"},
  23. {"key": "local", "url": "http://127.0.0.1:8000/api",
  24. "version": "开发机", "domain": "独立库", "bucket": "local"},
  25. ]
  26. ONLINE_URLS = [s["url"] for s in SITES if s["bucket"] == "online"]
  27. LOCAL_URL = next(s["url"] for s in SITES if s["key"] == "local")
  28. BUCKET_BY_URL = {s["url"]: s["bucket"] for s in SITES}
  29. DEFAULT_API_URL = SITES[0]["url"]
  30. def normalize_api_url(url):
  31. url = url.rstrip("/")
  32. parsed = urllib.parse.urlparse(url)
  33. if parsed.scheme not in ("http", "https"):
  34. raise WpError(f"API 地址必须以 http:// 或 https:// 开头:{url}")
  35. host = (parsed.hostname or "").lower()
  36. if parsed.scheme == "http" and host not in ("127.0.0.1", "localhost", "::1"):
  37. raise WpError(f"只有 127.0.0.1 / localhost 允许用 http://,其余必须 https://:{url}")
  38. return url
  39. def expand_site_alias(value):
  40. """把序号 / 简称展开成完整 url;已是 url 则原样返回。"""
  41. value = value.strip()
  42. if value.isdigit():
  43. idx = int(value) - 1
  44. if 0 <= idx < len(SITES):
  45. return SITES[idx]["url"]
  46. raise WpError(f"站点序号超出范围:{value}(可选 1-{len(SITES)})")
  47. for site in SITES:
  48. if value == site["key"]:
  49. return site["url"]
  50. if "://" in value:
  51. return value
  52. raise WpError(
  53. f"无法识别的站点:{value}。可用简称:" + " / ".join(s["key"] for s in SITES) + ",或直接给完整 url"
  54. )
  55. def site_label(api_url):
  56. for site in SITES:
  57. if site["url"] == api_url:
  58. return f"{site['version']} · {site['domain']}"
  59. return "自定义地址"