From 3e390068229eca9fcfb4c19454d3c4b6cc82d426 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Wed, 11 Feb 2026 16:32:40 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=2086=EC=9C=BC=EB=A1=9C=20=EC=88=98=ED=96=89=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/training/common/utils/FIleChecker.java | 94 ++++++++++++++ .../dataset/DatasetApiController.java | 3 +- .../dataset/service/DatasetService.java | 118 ++++++++++++++++++ 3 files changed, 214 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kamco/cd/training/common/utils/FIleChecker.java b/src/main/java/com/kamco/cd/training/common/utils/FIleChecker.java index 753b134..86da369 100644 --- a/src/main/java/com/kamco/cd/training/common/utils/FIleChecker.java +++ b/src/main/java/com/kamco/cd/training/common/utils/FIleChecker.java @@ -2,6 +2,7 @@ package com.kamco.cd.training.common.utils; import static java.lang.String.CASE_INSENSITIVE_ORDER; +import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; @@ -800,4 +801,97 @@ public class FIleChecker { if (session != null) session.disconnect(); } } + + public static void unzipOn86Server(String zipPath, String targetDir) { + + String host = "192.168.2.86"; + String user = "kcomu"; + String password = "Kamco2025!"; + + Session session = null; + ChannelExec channel = null; + + try { + JSch jsch = new JSch(); + + session = jsch.getSession(user, host, 22); + session.setPassword(password); + + Properties config = new Properties(); + config.put("StrictHostKeyChecking", "no"); + session.setConfig(config); + + session.connect(10_000); + + String command = "unzip -o " + zipPath + " -d " + targetDir; + + channel = (ChannelExec) session.openChannel("exec"); + channel.setCommand(command); + channel.setErrStream(System.err); + + InputStream in = channel.getInputStream(); + channel.connect(); + + // 출력 읽기(선택) + try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { + while (br.readLine() != null) { + // 필요하면 로그 + } + } + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (channel != null) channel.disconnect(); + if (session != null) session.disconnect(); + } + } + + public static List execCommandAndReadLines(String command) { + + List result = new ArrayList<>(); + + String host = "192.168.2.86"; + String user = "kcomu"; + String password = "Kamco2025!"; + + Session session = null; + ChannelExec channel = null; + + try { + JSch jsch = new JSch(); + + session = jsch.getSession(user, host, 22); + session.setPassword(password); + + Properties config = new Properties(); + config.put("StrictHostKeyChecking", "no"); + session.setConfig(config); + + session.connect(10_000); + + channel = (ChannelExec) session.openChannel("exec"); + channel.setCommand(command); + channel.setInputStream(null); + + InputStream in = channel.getInputStream(); + channel.connect(); + + try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { + String line; + while ((line = br.readLine()) != null) { + result.add(line); + } + } + + return result; + + } catch (Exception e) { + throw new RuntimeException("remote command failed : " + command, e); + + } finally { + if (channel != null) channel.disconnect(); + if (session != null) session.disconnect(); + } + } } diff --git a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java index 02417b2..c44ff3a 100644 --- a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java +++ b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java @@ -221,7 +221,8 @@ public class DatasetApiController { public ApiResponseDto insertDataset( @RequestBody @Valid DatasetDto.AddReq addReq) { - return ApiResponseDto.ok(datasetService.insertDataset(addReq)); + return ApiResponseDto.ok( + datasetService.insertDatasetTo86(addReq)); // TODO 서버 옮긴 이후에 다시 insertDataset 로 원복하기 } @Operation(summary = "객체별 파일 Path 조회", description = "파일 Path 조회") diff --git a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java index c27503f..967647c 100644 --- a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java +++ b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java @@ -158,6 +158,43 @@ public class DatasetService { } } + @Transactional + public ResponseObj insertDatasetTo86(@Valid AddReq addReq) { + + Long datasetUid = null; // master id 값, 등록하면서 가져올 예정 + + // 압축 해제 + FIleChecker.unzipOn86Server( + addReq.getFilePath() + addReq.getFileName(), + addReq.getFilePath() + addReq.getFileName().replace(".zip", "")); + + // 해제한 폴더 읽어서 데이터 저장 + List> list = + getUnzipDatasetFilesTo86( + addReq.getFilePath() + addReq.getFileName().replace(".zip", ""), "train"); + + int idx = 0; + for (Map map : list) { + datasetUid = + this.insertTrainTestData(map, addReq, idx, datasetUid, "train"); // train 데이터 insert + idx++; + } + + List> testList = + getUnzipDatasetFilesTo86( + addReq.getFilePath() + addReq.getFileName().replace(".zip", ""), "test"); + + int testIdx = 0; + for (Map test : testList) { + datasetUid = + this.insertTrainTestData(test, addReq, testIdx, datasetUid, "test"); // test 데이터 insert + testIdx++; + } + + datasetCoreService.updateDatasetUploadStatus(datasetUid); + return new ResponseObj(ApiResponseCode.OK, "업로드 성공하였습니다."); + } + @Transactional public ResponseObj insertDataset(@Valid AddReq addReq) { @@ -356,4 +393,85 @@ public class DatasetService { public String getFilePathByUUIDPathType(UUID uuid, String pathType) { return datasetCoreService.getFilePathByUUIDPathType(uuid, pathType); } + + private List> getUnzipDatasetFilesTo86(String unzipRootPath, String subDir) { + + // String root = Paths.get(unzipRootPath) + // .resolve(subDir) + // .toString(); + // + String root = normalizeLinuxPath(unzipRootPath + "/" + subDir); + + Map> grouped = new HashMap<>(); + + for (String dirName : LABEL_DIRS) { + + String remoteDir = root + "/" + dirName; + + // 1. 86 서버에서 해당 디렉토리의 파일 목록 조회 + List files = listFilesOn86Server(remoteDir); + + if (files.isEmpty()) { + throw new IllegalStateException("폴더가 존재하지 않거나 파일이 없습니다 : " + remoteDir); + } + + for (String fullPath : files) { + + String fileName = Paths.get(fullPath).getFileName().toString(); + String baseName = getBaseName(fileName); + + Map data = grouped.computeIfAbsent(baseName, k -> new HashMap<>()); + + data.put("baseName", baseName); + + if ("label-json".equals(dirName)) { + + // 2. json 내용도 86 서버에서 읽어서 가져와야 함 + String json = readRemoteFileAsString(fullPath); + + data.put("label-json", parseJson(json)); + data.put("geojson_path", fullPath); + + } else { + + data.put(dirName, fullPath); + } + } + } + + return new ArrayList<>(grouped.values()); + } + + private List listFilesOn86Server(String remoteDir) { + + String command = "find " + escape(remoteDir) + " -maxdepth 1 -type f"; + + return FIleChecker.execCommandAndReadLines(command); + } + + private String readRemoteFileAsString(String remoteFilePath) { + + String command = "cat " + escape(remoteFilePath); + + List lines = FIleChecker.execCommandAndReadLines(command); + + return String.join("\n", lines); + } + + private JsonNode parseJson(String json) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readTree(json); + } catch (IOException e) { + throw new RuntimeException("JSON 파싱 실패", e); + } + } + + private String escape(String path) { + return "'" + path.replace("'", "'\"'\"'") + "'"; + } + + private static String normalizeLinuxPath(String path) { + return path.replace("\\", "/"); + } } -- 2.49.1