refactor: backend→lotto 서비스 리네이밍 + lotto.db 레거시 테이블 스키마 제거
- backend/ → lotto/ 디렉토리 이동 - docker-compose: lotto-backend→lotto, lotto-frontend→frontend - deploy scripts, nginx, agent-office config 네이밍 일괄 반영 - lotto/app/db.py에서 todos·blog_posts CREATE TABLE 제거 (personal로 이관 완료) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
85
lotto/app/collector.py
Normal file
85
lotto/app/collector.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import requests
|
||||
from typing import Dict, Any
|
||||
|
||||
from .db import get_draw, upsert_draw, upsert_many_draws, get_latest_draw, count_draws
|
||||
|
||||
def _normalize_item(item: dict) -> dict:
|
||||
# smok95 all.json / latest.json 구조
|
||||
# - draw_no: int
|
||||
# - numbers: [n1..n6]
|
||||
# - bonus_no: int
|
||||
# - date: "YYYY-MM-DD ..."
|
||||
numbers = item["numbers"]
|
||||
return {
|
||||
"drw_no": int(item["draw_no"]),
|
||||
"drw_date": (item.get("date") or "")[:10],
|
||||
"n1": int(numbers[0]),
|
||||
"n2": int(numbers[1]),
|
||||
"n3": int(numbers[2]),
|
||||
"n4": int(numbers[3]),
|
||||
"n5": int(numbers[4]),
|
||||
"n6": int(numbers[5]),
|
||||
"bonus": int(item["bonus_no"]),
|
||||
}
|
||||
|
||||
def sync_all_from_json(all_url: str) -> Dict[str, Any]:
|
||||
r = requests.get(all_url, timeout=60)
|
||||
r.raise_for_status()
|
||||
data = r.json() # list[dict]
|
||||
|
||||
# 정규화
|
||||
rows = [_normalize_item(item) for item in data]
|
||||
|
||||
# Bulk Insert (성능 향상)
|
||||
upsert_many_draws(rows)
|
||||
|
||||
return {"mode": "all_json", "url": all_url, "total": len(rows)}
|
||||
|
||||
def sync_latest(latest_url: str) -> Dict[str, Any]:
|
||||
r = requests.get(latest_url, timeout=30)
|
||||
r.raise_for_status()
|
||||
item = r.json()
|
||||
|
||||
row = _normalize_item(item)
|
||||
before = get_draw(row["drw_no"])
|
||||
upsert_draw(row)
|
||||
|
||||
return {"mode": "latest_json", "url": latest_url, "was_new": (before is None), "drawNo": row["drw_no"]}
|
||||
|
||||
def sync_ensure_all(latest_url: str, all_url: str) -> Dict[str, Any]:
|
||||
"""
|
||||
1회부터 최신 회차까지 빠짐없이 있는지 확인하고, 없으면 전체 동기화 수행.
|
||||
반환값: {"synced": bool, "reason": str, ...}
|
||||
"""
|
||||
# 1. 원격 최신 회차 확인
|
||||
try:
|
||||
r = requests.get(latest_url, timeout=10)
|
||||
r.raise_for_status()
|
||||
remote_item = r.json()
|
||||
remote_no = int(remote_item["draw_no"])
|
||||
except Exception as e:
|
||||
# 외부 통신 실패 시, 그냥 로컬 데이터로 진행하도록 에러 억제 (혹은 에러 발생)
|
||||
# 여기서는 통계 기능 작동이 우선이므로 로그만 남기고 pass하고 싶지만,
|
||||
# 확실한 동기화를 위해 에러를 던지거나 False 리턴
|
||||
return {"synced": False, "error": str(e)}
|
||||
|
||||
# 2. 로컬 상태 확인
|
||||
local_latest_row = get_latest_draw()
|
||||
local_no = local_latest_row["drw_no"] if local_latest_row else 0
|
||||
local_cnt = count_draws()
|
||||
|
||||
# 3. 동기화 필요 여부 판단
|
||||
# - 전체 개수가 최신 회차 번호보다 적으면 중간에 빈 것 (1회부터 시작한다고 가정)
|
||||
# - 혹은 DB 최신 번호가 원격보다 낮으면 업데이트 필요
|
||||
need_sync = (local_no < remote_no) or (local_cnt < local_no)
|
||||
|
||||
if not need_sync:
|
||||
return {"synced": True, "updated": False, "local_no": local_no}
|
||||
|
||||
# 4. 전체 동기화 실행
|
||||
# (단순 latest sync로는 중간 구멍을 못 채우므로, 구멍이 있거나 차이가 크면 all_sync 수행)
|
||||
# 만약 차이가 1회차 뿐이고 구멍이 없다면 sync_latest만 해도 되지만,
|
||||
# 로직 단순화를 위해 missing 감지 시 그냥 all_sync (Bulk Insert라 빠름)
|
||||
res = sync_all_from_json(all_url)
|
||||
return {"synced": True, "updated": True, "detail": res}
|
||||
|
||||
Reference in New Issue
Block a user