- Frontend: ChnPrmShipInfo 타입 + chnPrmShip.ts 서비스 (signal-batch 허가어선 API) - Frontend: FieldAnalysisModal fetchVesselPermit → lookupPermittedShip 교체 - Frontend: 더미 라벨 정리 (LightGBM → 규칙기반, BD-09/레이더 → STANDBY/미연동) - Frontend: VesselAnalysisResult 인터페이스 정의 (Python 분석 결과 수신용) - Backend: vessel-analysis REST API (Entity/Repository/Service/Controller) - Backend: DB 마이그레이션 005 (kcg.vessel_analysis_results 테이블) - Backend: AuthFilter 인증 예외 + CacheConfig 캐시 등록 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import type { ChnPrmShipInfo } from '../types';
|
|
|
|
const SIGNAL_BATCH_BASE = '/signal-batch';
|
|
const CACHE_TTL_MS = 5 * 60_000; // 5분
|
|
|
|
let cachedList: ChnPrmShipInfo[] = [];
|
|
let cacheTime = 0;
|
|
let fetchPromise: Promise<ChnPrmShipInfo[]> | null = null;
|
|
|
|
async function fetchList(): Promise<ChnPrmShipInfo[]> {
|
|
const now = Date.now();
|
|
if (cachedList.length > 0 && now - cacheTime < CACHE_TTL_MS) {
|
|
return cachedList;
|
|
}
|
|
|
|
if (fetchPromise) return fetchPromise;
|
|
|
|
fetchPromise = (async () => {
|
|
try {
|
|
const res = await fetch(
|
|
`${SIGNAL_BATCH_BASE}/api/v2/vessels/chnprmship/recent-positions?minutes=60`,
|
|
{ headers: { accept: 'application/json' } },
|
|
);
|
|
if (!res.ok) return cachedList;
|
|
const json: unknown = await res.json();
|
|
cachedList = Array.isArray(json) ? (json as ChnPrmShipInfo[]) : [];
|
|
cacheTime = Date.now();
|
|
return cachedList;
|
|
} catch {
|
|
return cachedList;
|
|
} finally {
|
|
fetchPromise = null;
|
|
}
|
|
})();
|
|
|
|
return fetchPromise;
|
|
}
|
|
|
|
/** mmsi로 허가어선 정보 조회 — 목록을 캐시하고 lookup */
|
|
export async function lookupPermittedShip(mmsi: string): Promise<ChnPrmShipInfo | null> {
|
|
const list = await fetchList();
|
|
return list.find((s) => s.mmsi === mmsi) ?? null;
|
|
}
|
|
|
|
/** 허가어선 mmsi Set (빠른 조회용) */
|
|
export async function getPermittedMmsiSet(): Promise<Set<string>> {
|
|
const list = await fetchList();
|
|
return new Set(list.map((s) => s.mmsi));
|
|
}
|
|
|
|
/** 캐시 강제 갱신 */
|
|
export function invalidateCache(): void {
|
|
cacheTime = 0;
|
|
}
|