summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sedp/sedp-token.ts125
1 files changed, 85 insertions, 40 deletions
diff --git a/lib/sedp/sedp-token.ts b/lib/sedp/sedp-token.ts
index 0aa3b185..bd9451c1 100644
--- a/lib/sedp/sedp-token.ts
+++ b/lib/sedp/sedp-token.ts
@@ -3,64 +3,109 @@ const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.sh
const SEDP_API_USER_ID = process.env.SEDP_API_USER_ID || 'EVCPUSER';
const SEDP_API_PASSWORD = process.env.SEDP_API_PASSWORD || 'evcpusr@2025';
+// 토큰 캐시 (1시간 동안 유효)
+let cachedToken: string | null = null;
+let tokenExpiresAt: number | null = null;
+const TOKEN_VALIDITY_MS = 5 * 60 * 1000; // 5분 (밀리초)
+
+/**
+ * SEDP API에서 인증 토큰을 요청합니다.
+ * 내부 헬퍼 함수로, 실제 API 호출을 수행합니다.
+ */
+async function requestNewToken(): Promise<string> {
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Security/RequestTokenWithMembership`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*'
+ },
+ body: JSON.stringify({
+ UserID: SEDP_API_USER_ID,
+ Password: SEDP_API_PASSWORD
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`SEDP 토큰 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 응답이 직접 토큰 문자열인 경우
+ const tokenData = await response.text();
+
+ // 응답이 JSON 형식이면 파싱
+ try {
+ const jsonData = JSON.parse(tokenData);
+ if (typeof jsonData === 'string') {
+ return jsonData; // JSON 문자열이지만 내용물이 토큰 문자열인 경우
+ } else if (jsonData.Token) {
+ return jsonData.Token; // { Token: "..." } 형태인 경우
+ } else {
+ console.warn('예상치 못한 토큰 응답 형식:', jsonData);
+ // 가장 가능성 있는 필드를 찾아봄
+ for (const key of ['token', 'accessToken', 'access_token', 'Token', 'jwt']) {
+ if (jsonData[key]) return jsonData[key];
+ }
+ // 그래도 없으면 문자열로 변환
+ return JSON.stringify(jsonData);
+ }
+ } catch {
+ // 파싱 실패 = 응답이 JSON이 아닌 순수 토큰 문자열
+ return tokenData.trim();
+ }
+}
+
/**
* SEDP API에서 인증 토큰을 가져옵니다.
- * 매 호출 시마다 새로운 토큰을 발급받습니다.
+ * 토큰을 1시간 동안 캐싱하여 재사용합니다.
+ * 캐시된 토큰이 없거나 만료된 경우에만 새로운 토큰을 요청합니다.
*/
export async function getSEDPToken(): Promise<string> {
try {
- const response = await fetch(
- `${SEDP_API_BASE_URL}/Security/RequestTokenWithMembership`,
- {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'accept': '*/*'
- },
- body: JSON.stringify({
- UserID: SEDP_API_USER_ID,
- Password: SEDP_API_PASSWORD
- })
- }
- );
+ // 현재 시간
+ const now = Date.now();
- if (!response.ok) {
- throw new Error(`SEDP 토큰 요청 실패: ${response.status} ${response.statusText}`);
+ // 캐시된 토큰이 있고 아직 유효한 경우
+ if (cachedToken && tokenExpiresAt && now < tokenExpiresAt) {
+ console.log(`SEDP 토큰 캐시 사용 (만료까지 ${Math.round((tokenExpiresAt - now) / 1000 / 60)}분 남음)`);
+ return cachedToken;
}
- // 응답이 직접 토큰 문자열인 경우
- const tokenData = await response.text();
+ // 새로운 토큰 요청
+ console.log('SEDP 새 토큰 요청 중...');
+ const token = await requestNewToken();
- // 응답이 JSON 형식이면 파싱
- try {
- const jsonData = JSON.parse(tokenData);
- if (typeof jsonData === 'string') {
- return jsonData; // JSON 문자열이지만 내용물이 토큰 문자열인 경우
- } else if (jsonData.Token) {
- return jsonData.Token; // { Token: "..." } 형태인 경우
- } else {
- console.warn('예상치 못한 토큰 응답 형식:', jsonData);
- // 가장 가능성 있는 필드를 찾아봄
- for (const key of ['token', 'accessToken', 'access_token', 'Token', 'jwt']) {
- if (jsonData[key]) return jsonData[key];
- }
- // 그래도 없으면 문자열로 변환
- return JSON.stringify(jsonData);
- }
- } catch (e) {
- // 파싱 실패 = 응답이 JSON이 아닌 순수 토큰 문자열
- return tokenData.trim();
- }
+ // 캐시에 저장
+ cachedToken = token;
+ tokenExpiresAt = now + TOKEN_VALIDITY_MS;
+
+ console.log('SEDP 토큰 발급 완료 (1시간 유효)');
+ return token;
} catch (error) {
console.error('SEDP 토큰 가져오기 실패:', error);
+ // 오류 발생 시 캐시 초기화
+ cachedToken = null;
+ tokenExpiresAt = null;
throw error;
}
}
/**
+ * 캐시된 토큰을 강제로 무효화합니다.
+ * 토큰이 만료되었거나 인증 오류가 발생한 경우 호출할 수 있습니다.
+ */
+export function invalidateSEDPToken(): void {
+ console.log('SEDP 토큰 캐시 무효화');
+ cachedToken = null;
+ tokenExpiresAt = null;
+}
+
+/**
* SEDP API에 인증된 요청을 보냅니다.
*/
-export async function fetchSEDP(endpoint: string, options: RequestInit = {}): Promise<any> {
+export async function fetchSEDP(endpoint: string, options: RequestInit = {}): Promise<unknown> {
try {
// 토큰 가져오기
const token = await getSEDPToken();