kokokoasd commited on
Commit
da9f558
·
verified ·
1 Parent(s): ba001b6

Upload 20 files

Browse files
Files changed (1) hide show
  1. routers/backup.py +11 -74
routers/backup.py CHANGED
@@ -10,12 +10,10 @@ Requires env var:
10
  """
11
 
12
  import os
13
- import socket
14
  import shutil
15
  import tarfile
16
  from datetime import datetime
17
  from pathlib import Path
18
- from urllib.parse import urlparse
19
 
20
  import httpx
21
  from fastapi import APIRouter, HTTPException, BackgroundTasks, Request
@@ -25,76 +23,15 @@ from storage import load_meta, save_meta, validate_zone_name
25
 
26
  router = APIRouter(prefix="/api/backup", tags=["backup"])
27
 
28
- # ── Resolve Worker IP at startup to avoid DNS issues in HF Spaces ──
29
- _worker_ip: str | None = None
30
 
31
- def _resolve_worker_ip() -> str | None:
32
- """Resolve the Worker hostname to an IP address using system + fallback DNS."""
33
- global _worker_ip
34
- if _worker_ip:
35
- return _worker_ip
36
- if not ADMIN_API_URL:
37
- return None
38
- hostname = urlparse(ADMIN_API_URL).hostname
39
- if not hostname:
40
- return None
41
- # Try system DNS first
42
- try:
43
- _worker_ip = socket.getaddrinfo(hostname, 443, socket.AF_INET)[0][4][0]
44
- return _worker_ip
45
- except socket.gaierror:
46
- pass
47
- # Fallback: query Cloudflare DNS over HTTPS
48
- try:
49
- import json
50
- from urllib.request import urlopen, Request as UrlRequest
51
- req = UrlRequest(
52
- f"https://1.1.1.1/dns-query?name={hostname}&type=A",
53
- headers={"Accept": "application/dns-json"},
54
- )
55
- with urlopen(req, timeout=5) as resp:
56
- data = json.loads(resp.read())
57
- for ans in data.get("Answer", []):
58
- if ans.get("type") == 1: # A record
59
- _worker_ip = ans["data"]
60
- return _worker_ip
61
- except Exception:
62
- pass
63
- return None
64
-
65
-
66
- def _make_client(timeout: int = 30) -> httpx.AsyncClient:
67
- """Create an httpx AsyncClient."""
68
- return httpx.AsyncClient(timeout=timeout)
69
-
70
-
71
- def _make_sync_client(timeout: int = 300) -> httpx.Client:
72
- """Create a sync httpx Client."""
73
- return httpx.Client(timeout=timeout)
74
 
75
 
76
  def _url(path: str) -> str:
77
- """Build the full Worker URL for a given path, using resolved IP if needed."""
78
- full = f"{ADMIN_API_URL}{path}"
79
- ip = _resolve_worker_ip()
80
- if ip:
81
- hostname = urlparse(ADMIN_API_URL).hostname or ""
82
- return full.replace(hostname, ip)
83
- return full
84
-
85
-
86
- def _host_header() -> dict:
87
- """Return Host header if using IP-resolved URL."""
88
- ip = _resolve_worker_ip()
89
- if ip:
90
- hostname = urlparse(ADMIN_API_URL).hostname or ""
91
- return {"Host": hostname}
92
- return {}
93
-
94
-
95
- def _worker_headers(token: str) -> dict:
96
- """Build headers for Worker API calls."""
97
- return {"Authorization": f"Bearer {token}", **_host_header()}
98
 
99
 
100
  def _get_token(request: Request) -> str:
@@ -140,7 +77,7 @@ async def list_backups(request: Request):
140
  if not token:
141
  raise HTTPException(401, "Chua dang nhap")
142
  try:
143
- async with _make_client(timeout=30) as client:
144
  resp = await client.get(_url("/backup/list"), headers=_worker_headers(token))
145
  if resp.status_code != 200:
146
  data = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {"error": resp.text}
@@ -173,7 +110,7 @@ async def backup_zone(zone_name: str, request: Request, background_tasks: Backgr
173
  try:
174
  archive_path = _create_zone_archive(zone_name)
175
  try:
176
- with _make_sync_client(timeout=300) as client:
177
  with open(archive_path, "rb") as f:
178
  resp = client.post(
179
  _url(f"/backup/upload/{zone_name}"),
@@ -221,7 +158,7 @@ async def backup_all(request: Request, background_tasks: BackgroundTasks):
221
  _backup_status["progress"] = f"Dang backup zone {zone_name} ({done + 1}/{total})..."
222
  archive_path = _create_zone_archive(zone_name)
223
  try:
224
- with _make_sync_client(timeout=300) as client:
225
  with open(archive_path, "rb") as f:
226
  resp = client.post(
227
  _url(f"/backup/upload/{zone_name}"),
@@ -264,7 +201,7 @@ async def restore_zone(zone_name: str, request: Request, background_tasks: Backg
264
  _backup_status["error"] = None
265
  _backup_status["progress"] = f"Dang restore zone: {zone_name}..."
266
  try:
267
- with _make_sync_client(timeout=300) as client:
268
  resp = client.get(_url(f"/backup/download/{zone_name}"), headers=_worker_headers(token))
269
  if resp.status_code == 404:
270
  raise ValueError(f"Backup zone '{zone_name}' khong ton tai")
@@ -319,7 +256,7 @@ async def restore_all(request: Request, background_tasks: BackgroundTasks):
319
  _backup_status["error"] = None
320
  _backup_status["progress"] = "Dang restore tat ca zones..."
321
  try:
322
- with _make_sync_client(timeout=30) as client:
323
  resp = client.get(_url("/backup/list"), headers=_worker_headers(token))
324
  if resp.status_code != 200:
325
  raise ValueError(f"Khong the lay danh sach backup: {resp.text}")
@@ -330,7 +267,7 @@ async def restore_all(request: Request, background_tasks: BackgroundTasks):
330
  for b in backup_list:
331
  zone_name = b["zone_name"]
332
  _backup_status["progress"] = f"Dang restore zone {zone_name} ({done + 1}/{total})..."
333
- with _make_sync_client(timeout=300) as client:
334
  resp = client.get(_url(f"/backup/download/{zone_name}"), headers=_worker_headers(token))
335
  if resp.status_code != 200:
336
  continue
 
10
  """
11
 
12
  import os
 
13
  import shutil
14
  import tarfile
15
  from datetime import datetime
16
  from pathlib import Path
 
17
 
18
  import httpx
19
  from fastapi import APIRouter, HTTPException, BackgroundTasks, Request
 
23
 
24
  router = APIRouter(prefix="/api/backup", tags=["backup"])
25
 
 
 
26
 
27
+ def _worker_headers(token: str) -> dict:
28
+ """Build headers for Worker API calls."""
29
+ return {"Authorization": f"Bearer {token}"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
 
32
  def _url(path: str) -> str:
33
+ """Build the full Worker URL for a given path."""
34
+ return f"{ADMIN_API_URL}{path}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
 
37
  def _get_token(request: Request) -> str:
 
77
  if not token:
78
  raise HTTPException(401, "Chua dang nhap")
79
  try:
80
+ async with httpx.AsyncClient(timeout=30) as client:
81
  resp = await client.get(_url("/backup/list"), headers=_worker_headers(token))
82
  if resp.status_code != 200:
83
  data = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {"error": resp.text}
 
110
  try:
111
  archive_path = _create_zone_archive(zone_name)
112
  try:
113
+ with httpx.Client(timeout=300) as client:
114
  with open(archive_path, "rb") as f:
115
  resp = client.post(
116
  _url(f"/backup/upload/{zone_name}"),
 
158
  _backup_status["progress"] = f"Dang backup zone {zone_name} ({done + 1}/{total})..."
159
  archive_path = _create_zone_archive(zone_name)
160
  try:
161
+ with httpx.Client(timeout=300) as client:
162
  with open(archive_path, "rb") as f:
163
  resp = client.post(
164
  _url(f"/backup/upload/{zone_name}"),
 
201
  _backup_status["error"] = None
202
  _backup_status["progress"] = f"Dang restore zone: {zone_name}..."
203
  try:
204
+ with httpx.Client(timeout=300) as client:
205
  resp = client.get(_url(f"/backup/download/{zone_name}"), headers=_worker_headers(token))
206
  if resp.status_code == 404:
207
  raise ValueError(f"Backup zone '{zone_name}' khong ton tai")
 
256
  _backup_status["error"] = None
257
  _backup_status["progress"] = "Dang restore tat ca zones..."
258
  try:
259
+ with httpx.Client(timeout=30) as client:
260
  resp = client.get(_url("/backup/list"), headers=_worker_headers(token))
261
  if resp.status_code != 200:
262
  raise ValueError(f"Khong the lay danh sach backup: {resp.text}")
 
267
  for b in backup_list:
268
  zone_name = b["zone_name"]
269
  _backup_status["progress"] = f"Dang restore zone {zone_name} ({done + 1}/{total})..."
270
+ with httpx.Client(timeout=300) as client:
271
  resp = client.get(_url(f"/backup/download/{zone_name}"), headers=_worker_headers(token))
272
  if resp.status_code != 200:
273
  continue