135 lines
4.4 KiB
JavaScript
135 lines
4.4 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
|
||
|
|
// 요청 예시: https://www.everfactory.kr/api/contents/update?date=YYYYMMDD
|
||
|
|
// 사용법
|
||
|
|
// 1) 오늘(가장 최신)부터 특정 일자까지 요청:
|
||
|
|
// node datareq/datareq.js 20251014
|
||
|
|
// 2) 특정 최신일자부터 특정 과거일자까지 요청:
|
||
|
|
// node datareq/datareq.js 20251015 20251001
|
||
|
|
// 환경변수로 호출 간 지연(ms) 조절: RATE_MS=500 node datareq/datareq.js 20251014
|
||
|
|
|
||
|
|
const BASE_URL = "http://localhost:9551/api/contents/update";
|
||
|
|
const DEFAULT_RATE_MS = Number(process.env.RATE_MS || 400);
|
||
|
|
|
||
|
|
function isValidYyyyMmDd(value) {
|
||
|
|
return typeof value === "string" && /^\d{8}$/.test(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
function truncateText(text, maxLen = 256) {
|
||
|
|
if (typeof text !== "string") return "";
|
||
|
|
return text.length > maxLen ? text.slice(0, maxLen) : text;
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseYyyyMmDdToDate(yyyyMmDd) {
|
||
|
|
const year = Number(yyyyMmDd.slice(0, 4));
|
||
|
|
const month = Number(yyyyMmDd.slice(4, 6)) - 1; // 0-based
|
||
|
|
const day = Number(yyyyMmDd.slice(6, 8));
|
||
|
|
// Date(YYYY, M, D)는 로컬 타임존 기준. 간단성을 위해 로컬 기준 사용.
|
||
|
|
return new Date(year, month, day);
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatDateToYyyyMmDd(date) {
|
||
|
|
const y = String(date.getFullYear());
|
||
|
|
const m = String(date.getMonth() + 1).padStart(2, "0");
|
||
|
|
const d = String(date.getDate()).padStart(2, "0");
|
||
|
|
return `${y}${m}${d}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function addDays(date, delta) {
|
||
|
|
const next = new Date(date);
|
||
|
|
next.setDate(next.getDate() + delta);
|
||
|
|
return next;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function sleep(ms) {
|
||
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
|
|
}
|
||
|
|
|
||
|
|
async function requestForDate(dateStr) {
|
||
|
|
const url = `${BASE_URL}?date=${dateStr}`;
|
||
|
|
try {
|
||
|
|
const res = await fetch(url, { method: "GET" });
|
||
|
|
const text = await res.text().catch(() => "");
|
||
|
|
if (!res.ok) {
|
||
|
|
const preview = truncateText(text, 256);
|
||
|
|
console.error(`[FAIL] ${dateStr} | ${url} -> ${res.status} ${res.statusText} ${preview ? `| ${preview}` : ""}`);
|
||
|
|
return { ok: false, status: res.status, body: text };
|
||
|
|
}
|
||
|
|
const preview = truncateText(text, 256);
|
||
|
|
console.log(`[OK] ${dateStr} | ${url} -> ${preview || res.status}`);
|
||
|
|
return { ok: true, status: res.status, body: text };
|
||
|
|
} catch (err) {
|
||
|
|
const errMsg = err instanceof Error ? err.message : String(err);
|
||
|
|
console.error(`[ERROR] ${dateStr} | ${url} -> ${truncateText(errMsg, 256)}`);
|
||
|
|
return { ok: false, error: err };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
const args = process.argv.slice(2);
|
||
|
|
|
||
|
|
if (args.length === 0) {
|
||
|
|
console.log("사용법: node datareq/datareq.js <끝일자YYYYMMDD> [시작(최신)일자YYYYMMDD]");
|
||
|
|
console.log("예시1: node datareq/datareq.js 20251014");
|
||
|
|
console.log("예시2: node datareq/datareq.js 20251015 20251001");
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
let newestStr; // 최신일자 (내림차순 시작점)
|
||
|
|
let oldestStr; // 종료일자 (내림차순 끝점)
|
||
|
|
|
||
|
|
if (args.length === 1) {
|
||
|
|
const today = new Date();
|
||
|
|
newestStr = formatDateToYyyyMmDd(today);
|
||
|
|
oldestStr = args[0];
|
||
|
|
} else {
|
||
|
|
// args.length >= 2 인 경우: [최신일자, 종료일자]
|
||
|
|
newestStr = args[0];
|
||
|
|
oldestStr = args[1];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isValidYyyyMmDd(newestStr) || !isValidYyyyMmDd(oldestStr)) {
|
||
|
|
console.error("날짜 형식은 YYYYMMDD 여야 합니다.");
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
let newestDate = parseYyyyMmDdToDate(newestStr);
|
||
|
|
let oldestDate = parseYyyyMmDdToDate(oldestStr);
|
||
|
|
|
||
|
|
// 최신 >= 종료 가 아니면 자동 교환
|
||
|
|
if (newestDate < oldestDate) {
|
||
|
|
const tmp = newestDate;
|
||
|
|
newestDate = oldestDate;
|
||
|
|
oldestDate = tmp;
|
||
|
|
newestStr = formatDateToYyyyMmDd(newestDate);
|
||
|
|
oldestStr = formatDateToYyyyMmDd(oldestDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`요청 범위: 최신 ${newestStr} → 종료 ${oldestStr} (내림차순)`);
|
||
|
|
console.log(`요청 간 지연: ${DEFAULT_RATE_MS}ms`);
|
||
|
|
|
||
|
|
let current = newestDate;
|
||
|
|
while (current >= oldestDate) {
|
||
|
|
const dateStr = formatDateToYyyyMmDd(current);
|
||
|
|
await requestForDate(dateStr);
|
||
|
|
// 너무 빠른 연속 호출 방지
|
||
|
|
await sleep(DEFAULT_RATE_MS);
|
||
|
|
current = addDays(current, -1);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log("모든 요청이 완료되었습니다.");
|
||
|
|
}
|
||
|
|
|
||
|
|
// Node 18+ 환경 가정: fetch 전역 제공. 없으면 종료 안내.
|
||
|
|
if (typeof fetch !== "function") {
|
||
|
|
console.error("현재 Node 런타임에 fetch가 없습니다. Node 18+를 사용하거나 폴리필을 추가하세요.");
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((err) => {
|
||
|
|
console.error("예상치 못한 오류:", err);
|
||
|
|
process.exit(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
|