diff --git a/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/model/UtmDto.java b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/model/UtmDto.java new file mode 100644 index 0000000..b892938 --- /dev/null +++ b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/model/UtmDto.java @@ -0,0 +1,37 @@ +package kr.co.palnet.kac.socket.core.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UtmDto { + @JsonProperty("GPSime") + private String GPSime; // 시간 yyyyMMddHHmmss + @JsonProperty("droneInfo") + private List dronInfo; + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class DronInfo { + @JsonProperty("Id") + private String id; + @JsonProperty("Latitude") + private String latitude; + @JsonProperty("Longitude") + private String longitude; + @JsonProperty("Height") + private String height; + } + + +} diff --git a/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/storage/DronStorage.java b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/storage/DronStorage.java index 1a20f73..8cb4810 100644 --- a/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/storage/DronStorage.java +++ b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/core/storage/DronStorage.java @@ -60,22 +60,62 @@ public class DronStorage { } - public void removeScheduled() { - log.info("removeScheduled start - dronMap size : {}", dronMap.size()); + // 1분 이상된 데이터 삭제 또는 처리가 끝난 데이터 삭제 + public void removeByCondition() { for (String key : dronMap.keySet()) { List list = dronMap.get(key); - if (list == null || list.isEmpty()) { + if (list == null) { + continue; + } else if (list.isEmpty()) { + dronMap.remove(key); continue; } - DronDto dron = list.get(list.size() - 1); - // 1분 이상된 데이터 삭제 + + // 1분 전 시간 Instant compareTime = Instant.now().minusSeconds(60); - if (compareTime.isAfter(dron.getRegDt())) { -// log.info("remove data - 1 munite over : {}", key); - dronMap.remove(key); + + // 마지막 데이터가 1분 이상된 데이터라면 삭제 + DronDto lastDronDto = list.getLast(); + if ((lastDronDto.isSendHistroy() && lastDronDto.isSendUtm()) || compareTime.isAfter(lastDronDto.getRegDt())) { + list.remove(lastDronDto); + continue; } + + // 그외 데이터에서 조건에 맞는 데이터들만 삭제 + list.removeIf(dron -> (dron.isSendHistroy() && dron.isSendUtm()) || compareTime.isAfter(dron.getRegDt())); } - log.info("removeScheduled end - dronMap size : {}", dronMap.size()); + } + + public List getAllByUtm() { + // 보내지 않은 모든 데이터 추출 + return dronMap.values().stream().reduce((list, result) -> { + result.addAll(list); + return result; + }).orElse(new ArrayList<>()).stream().filter(dronDto -> !dronDto.isSendUtm()).toList(); + } + + public List getAllByHistory() { + // 보내지 않은 모든 데이터 추출 + return dronMap.values().stream().reduce((list, result) -> { + result.addAll(list); + return result; + }).orElse(new ArrayList<>()).stream().filter(dronDto -> !dronDto.isSendHistroy()).toList(); + } + + public static void main(String[] args) { + DronStorage dronStorage = DronStorage.getInstance(); + + DronDto dronDto = new DronDto(); + dronDto.setObjectId("test"); + dronDto.setSendHistroy(false); + dronDto.setSendUtm(false); + dronDto.setRegDt(Instant.now()); + + dronStorage.add(dronDto); + + List allByUtm = dronStorage.getAllByUtm(); + allByUtm.forEach(c -> c.setSendUtm(true)); + log.info("..."); } } \ No newline at end of file diff --git a/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ExternalService.java b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ExternalService.java new file mode 100644 index 0000000..9d15ded --- /dev/null +++ b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ExternalService.java @@ -0,0 +1,45 @@ +package kr.co.palnet.kac.socket.service; + +import kr.co.palnet.kac.socket.core.model.UtmDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ExternalService { + + public boolean sendDataToUtm(UtmDto utmDto) { + + // 임시 하드코딩 + final String UTM_HOST = "http://192.168.0.133:9000"; + final String UTM_REALTIME_URI = "/api/v1/utm"; + + RestClient client = RestClient.builder() + .baseUrl(UTM_HOST) + .defaultHeader("Content-Type", "application/json") + .build(); + + try { + + ResponseEntity res = client.post() + .uri(UTM_REALTIME_URI) + .body(utmDto) + .retrieve() + .toEntity(Void.class); + + if (res.getStatusCode() == HttpStatus.OK) { + return true; + } + } catch (Exception e) { + log.warn("fail send to utm. {}", e.getMessage()); + } + return false; + } + + +} diff --git a/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ScheduledService.java b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ScheduledService.java new file mode 100644 index 0000000..2918736 --- /dev/null +++ b/app/kac-socket-app/src/main/java/kr/co/palnet/kac/socket/service/ScheduledService.java @@ -0,0 +1,67 @@ +package kr.co.palnet.kac.socket.service; + +import kr.co.palnet.kac.common.model.common.DronDto; +import kr.co.palnet.kac.socket.core.model.UtmDto; +import kr.co.palnet.kac.socket.core.storage.DronStorage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ScheduledService { + + private final ExternalService externalService; + + @Scheduled(fixedDelay = 1000 * 2) + public void sendDataToUtm() { + log.info(">>>> sendDataToUtm <<<<<"); + DronStorage dronStorage = DronStorage.getInstance(); + List list = dronStorage.getAllByUtm(); + + // 가공 + List dronInfoList = list.stream().map(model -> { + UtmDto.DronInfo dronInfo = UtmDto.DronInfo.builder() + .id(model.getObjectId()) + .latitude(model.getLat().toString()) + .longitude(model.getLon().toString()) + .height(model.getElev().toString()) + .build(); + return dronInfo; + }).collect(Collectors.toList()); + + if (dronInfoList.isEmpty()) return; + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss") + .withZone(ZoneId.of("Asia/Seoul")); + String dateStr = formatter.format(Instant.now()); + + UtmDto utmDto = UtmDto.builder() + .GPSime(dateStr) + .dronInfo(dronInfoList) + .build(); + +// if (externalService.sendDataToUtm(utmDto)) { +// list.forEach(dron -> dron.setSendUtm(true)); +// } + + // TODO 현재 통신이 안되므로 모두 보낸다는 가정으로 진행 + list.forEach(dron -> dron.setSendUtm(true)); + + } + + @Scheduled(fixedDelay = 1000 * 30) + public void removeDron() { + log.info(">>>> removeDron <<<<<"); + DronStorage dronStorage = DronStorage.getInstance(); + dronStorage.removeByCondition(); + } +} diff --git a/common/model/src/main/java/kr/co/palnet/kac/common/model/common/DronDto.java b/common/model/src/main/java/kr/co/palnet/kac/common/model/common/DronDto.java index 6ff8dd5..4f58d68 100644 --- a/common/model/src/main/java/kr/co/palnet/kac/common/model/common/DronDto.java +++ b/common/model/src/main/java/kr/co/palnet/kac/common/model/common/DronDto.java @@ -91,6 +91,7 @@ public class DronDto { // 큐가 Socket서버에 도착한 시간 private Instant regDt; // 큐가 Socket서버에 도착한 시간 - private boolean sendUtm; // 불법드론 전송 여부 + private boolean isSendUtm; // 불법드론 전송 여부 + private boolean isSendHistroy; // 서버 전송 여부 }