Compare commits
1 커밋
main
...
feature/in
| 작성자 | SHA1 | 날짜 | |
|---|---|---|---|
| da7e8f0e41 |
@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [2026-03-27.3]
|
|
||||||
|
|
||||||
### 추가
|
|
||||||
- 비정상 궤적 포함 저장 플래그 (`include-abnormal-in-tracks`) — 강화학습 데이터 수집용
|
|
||||||
|
|
||||||
### 수정
|
|
||||||
- REST API 경로 client_id 수집 누락 수정 — JWT 쿠키 파싱 공용 메서드 추출
|
|
||||||
|
|
||||||
## [2026-03-27.2]
|
## [2026-03-27.2]
|
||||||
|
|
||||||
### 수정
|
### 수정
|
||||||
|
|||||||
@ -191,11 +191,7 @@ public class GisControllerV2 {
|
|||||||
)
|
)
|
||||||
@RequestBody VesselTracksRequest request,
|
@RequestBody VesselTracksRequest request,
|
||||||
HttpServletRequest httpRequest) {
|
HttpServletRequest httpRequest) {
|
||||||
return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest), getClientId(httpRequest));
|
return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest));
|
||||||
}
|
|
||||||
|
|
||||||
private String getClientId(HttpServletRequest request) {
|
|
||||||
return gc.mda.signal_batch.global.config.WebSocketStompConfig.extractClientIdFromRequest(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getClientIp(HttpServletRequest request) {
|
private String getClientIp(HttpServletRequest request) {
|
||||||
|
|||||||
@ -285,7 +285,7 @@ public class GisServiceV2 {
|
|||||||
/**
|
/**
|
||||||
* 선박별 항적 조회 V2 (캐시 + Semaphore + 간소화 + ChnPrmShip enrichment)
|
* 선박별 항적 조회 V2 (캐시 + Semaphore + 간소화 + ChnPrmShip enrichment)
|
||||||
*/
|
*/
|
||||||
public List<CompactVesselTrack> getVesselTracksV2(VesselTracksRequest request, String clientIp, String clientId) {
|
public List<CompactVesselTrack> getVesselTracksV2(VesselTracksRequest request, String clientIp) {
|
||||||
String queryId = "rest-vessels-" + UUID.randomUUID().toString().substring(0, 8);
|
String queryId = "rest-vessels-" + UUID.randomUUID().toString().substring(0, 8);
|
||||||
long startMs = System.currentTimeMillis();
|
long startMs = System.currentTimeMillis();
|
||||||
boolean slotAcquired = false;
|
boolean slotAcquired = false;
|
||||||
@ -329,7 +329,7 @@ public class GisServiceV2 {
|
|||||||
result.size(), request.getVessels().size(),
|
result.size(), request.getVessels().size(),
|
||||||
dailyTrackCacheManager.isEnabled(), request.isIncludeChnPrmShip());
|
dailyTrackCacheManager.isEnabled(), request.isIncludeChnPrmShip());
|
||||||
|
|
||||||
enqueueRestMetric(queryId, request, result, startMs, clientIp, clientId);
|
enqueueRestMetric(queryId, request, result, startMs, clientIp);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -347,7 +347,7 @@ public class GisServiceV2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enqueueRestMetric(String queryId, VesselTracksRequest request,
|
private void enqueueRestMetric(String queryId, VesselTracksRequest request,
|
||||||
List<CompactVesselTrack> result, long startMs, String clientIp, String clientId) {
|
List<CompactVesselTrack> result, long startMs, String clientIp) {
|
||||||
try {
|
try {
|
||||||
int totalPoints = result.stream().mapToInt(CompactVesselTrack::getPointCount).sum();
|
int totalPoints = result.stream().mapToInt(CompactVesselTrack::getPointCount).sum();
|
||||||
long responseBytes = (long) result.size() * 200 + (long) totalPoints * 40;
|
long responseBytes = (long) result.size() * 200 + (long) totalPoints * 40;
|
||||||
@ -367,7 +367,6 @@ public class GisServiceV2 {
|
|||||||
.elapsedMs(System.currentTimeMillis() - startMs)
|
.elapsedMs(System.currentTimeMillis() - startMs)
|
||||||
.status("COMPLETED")
|
.status("COMPLETED")
|
||||||
.clientIp(clientIp)
|
.clientIp(clientIp)
|
||||||
.clientId(clientId)
|
|
||||||
.build());
|
.build());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to enqueue REST metric: {}", e.getMessage());
|
log.debug("Failed to enqueue REST metric: {}", e.getMessage());
|
||||||
|
|||||||
@ -235,44 +235,42 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출.
|
||||||
|
* JWT 검증은 nginx auth_request에서 이미 완료 — 여기서는 payload 디코딩만 수행.
|
||||||
|
*/
|
||||||
private String extractEmailFromJwtCookie(HttpServletRequest request) {
|
private String extractEmailFromJwtCookie(HttpServletRequest request) {
|
||||||
return extractClientIdFromRequest(request);
|
Cookie[] cookies = request.getCookies();
|
||||||
}
|
if (cookies == null) return null;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
String token = null;
|
||||||
* GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출 (REST/WebSocket 공용).
|
for (Cookie cookie : cookies) {
|
||||||
* JWT 검증은 nginx auth_request에서 이미 완료 — 여기서는 payload 디코딩만 수행.
|
if ("GC_SESSION".equals(cookie.getName())) {
|
||||||
*/
|
token = cookie.getValue();
|
||||||
public static String extractClientIdFromRequest(HttpServletRequest request) {
|
break;
|
||||||
Cookie[] cookies = request.getCookies();
|
}
|
||||||
if (cookies == null) return null;
|
|
||||||
|
|
||||||
String token = null;
|
|
||||||
for (Cookie cookie : cookies) {
|
|
||||||
if ("GC_SESSION".equals(cookie.getName())) {
|
|
||||||
token = cookie.getValue();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if (token == null || token.isEmpty()) return null;
|
||||||
if (token == null || token.isEmpty()) return null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String[] parts = token.split("\\.");
|
// JWT: header.payload.signature — payload만 Base64URL 디코딩
|
||||||
if (parts.length < 2) return null;
|
String[] parts = token.split("\\.");
|
||||||
|
if (parts.length < 2) return null;
|
||||||
|
|
||||||
String payload = new String(Base64.getUrlDecoder().decode(parts[1]));
|
String payload = new String(Base64.getUrlDecoder().decode(parts[1]));
|
||||||
int emailIdx = payload.indexOf("\"email\"");
|
// 간단한 JSON 파싱 (Jackson 의존 없이): "email":"value" 추출
|
||||||
if (emailIdx < 0) return null;
|
int emailIdx = payload.indexOf("\"email\"");
|
||||||
|
if (emailIdx < 0) return null;
|
||||||
|
|
||||||
int colonIdx = payload.indexOf(':', emailIdx);
|
int colonIdx = payload.indexOf(':', emailIdx);
|
||||||
int quoteStart = payload.indexOf('"', colonIdx + 1);
|
int quoteStart = payload.indexOf('"', colonIdx + 1);
|
||||||
int quoteEnd = payload.indexOf('"', quoteStart + 1);
|
int quoteEnd = payload.indexOf('"', quoteStart + 1);
|
||||||
if (quoteStart < 0 || quoteEnd < 0) return null;
|
if (quoteStart < 0 || quoteEnd < 0) return null;
|
||||||
|
|
||||||
return payload.substring(quoteStart + 1, quoteEnd);
|
return payload.substring(quoteStart + 1, quoteEnd);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
불러오는 중...
Reference in New Issue
Block a user