package com.arms.api.util; import com.arms.config.GiteaUserConfig; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; @Component @RequiredArgsConstructor @Slf4j public class GiteaHttpURLConnection { private final GiteaUserConfig giteaUserConfig; // --- 저수준 메서드 (Low-level) --- /** * Basic Auth 인증이 설정된 HttpURLConnection을 생성합니다. * * @param url 요청 URL * @param method HTTP 메서드 (GET, POST, PUT, DELETE) * @return 인증 헤더가 설정된 HttpURLConnection */ @SuppressWarnings("java:S2647") public HttpURLConnection createConnection(String url, String method) throws Exception { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); String auth = giteaUserConfig.getGitUsername() + ":" + giteaUserConfig.getGitPassword(); String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); connection.setRequestMethod(method); connection.setRequestProperty("Authorization", "Basic " + encodedAuth); if ("POST".equals(method) || "PUT".equals(method) || "DELETE".equals(method)) { connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/json"); } return connection; } /** * GET 요청을 위한 인증된 연결을 생성합니다. * * @param url 요청 URL * @return 인증 헤더가 설정된 HttpURLConnection (GET) */ public HttpURLConnection createGetConnection(String url) throws Exception { return createConnection(url, "GET"); } /** * 연결의 응답 본문을 문자열로 읽습니다. * * @param connection 응답을 읽을 HttpURLConnection * @return 응답 본문 문자열 */ public String readResponseBody(HttpURLConnection connection) throws Exception { try (BufferedReader reader = new BufferedReader( new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } return sb.toString(); } } /** * 연결에 요청 본문을 씁니다. * * @param connection 요청 본문을 쓸 HttpURLConnection * @param body 요청 본문 문자열 */ public void writeRequestBody(HttpURLConnection connection, String body) throws Exception { try (OutputStream os = connection.getOutputStream()) { os.write(body.getBytes(StandardCharsets.UTF_8)); os.flush(); } } // --- 고수준 메서드 (파일 CRUD) --- /** * Gitea 저장소의 파일을 업데이트합니다. (PUT) * * @param apiUrl Gitea API 디렉토리 URL * @param fileName 업데이트할 파일명 * @param sha 기존 파일의 SHA 값 * @param branch 대상 브랜치 * @param contents 파일 내용 (평문 - 내부에서 Base64 인코딩) * @return HTTP 응답 코드 */ public int updateFile(String apiUrl, String fileName, String sha, String branch, String contents) throws Exception { HttpURLConnection connection = createConnection(apiUrl + fileName, "PUT"); String content = Base64.getEncoder().encodeToString(contents.getBytes(StandardCharsets.UTF_8)); String requestBody = String.format( "{\"content\":\"%s\",\"message\":\"Update %s\",\"sha\":\"%s\",\"branch\":\"%s\"}", content, fileName, sha, branch ); writeRequestBody(connection, requestBody); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { log.info("File {} updated successfully.", fileName); } else { log.error("Failed to update file {}. Response code: {}", fileName, responseCode); } return responseCode; } /** * Gitea 저장소에 새 파일을 생성합니다. (POST) * * @param apiUrl Gitea API 디렉토리 URL * @param fileName 생성할 파일명 * @param branch 대상 브랜치 * @param contents 파일 내용 (평문 - 내부에서 Base64 인코딩) * @return HTTP 응답 코드 */ public int createFile(String apiUrl, String fileName, String branch, String contents) throws Exception { HttpURLConnection connection = createConnection(apiUrl + fileName, "POST"); String content = Base64.getEncoder().encodeToString(contents.getBytes(StandardCharsets.UTF_8)); String requestBody = String.format( "{\"content\":\"%s\",\"message\":\"Create %s\",\"branch\":\"%s\"}", content, fileName, branch ); writeRequestBody(connection, requestBody); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_CREATED) { log.info("File {} created successfully.", fileName); } else { log.error("Failed to create file {}. Response code: {}", fileName, responseCode); } return responseCode; } /** * Gitea 저장소의 파일을 삭제합니다. (DELETE) * * @param apiUrl Gitea API 디렉토리 URL * @param fileName 삭제할 파일명 * @param sha 기존 파일의 SHA 값 * @param branch 대상 브랜치 * @return HTTP 응답 코드 */ public int deleteFile(String apiUrl, String fileName, String sha, String branch) throws Exception { HttpURLConnection connection = createConnection(apiUrl + fileName, "DELETE"); String requestBody = String.format( "{\"message\":\"Delete %s\",\"sha\":\"%s\",\"branch\":\"%s\"}", fileName, sha, branch ); writeRequestBody(connection, requestBody); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { log.info("File {} deleted successfully.", fileName); } else { log.error("Failed to delete file {}. Response code: {}", fileName, responseCode); } return responseCode; } }