package com.kaidi.oa.web; import com.kaidi.oa.common.ApiResp; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.sql.DataSource; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.Map; /** Readiness probe used by the installer and online-update rollback gate. */ @RestController @RequestMapping("/api/oa") public class HealthController { private final DataSource dataSource; private final Path installLockFile; public HealthController(DataSource dataSource, @Value("${ERP_INSTALL_LOCK_FILE:}") String installLockFile) { this.dataSource = dataSource; this.installLockFile = resolveInstallLockFile(installLockFile); } @GetMapping("/health") public ResponseEntity>> health() { try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement(); ResultSet result = statement.executeQuery("SELECT 1")) { if (connection.isValid(2) && result.next() && result.getInt(1) == 1) { return ResponseEntity.ok(ApiResp.ok(readiness("UP", "UP"))); } } catch (Exception ignored) { // Health responses deliberately avoid exposing connection details. } return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) .body(new ApiResp<>(50301, "database unavailable", readiness("DOWN", "DOWN"))); } private Map readiness(String status, String database) { return Map.of( "status", status, "database", database, "installLocked", Boolean.toString(installLockFile != null && Files.isRegularFile(installLockFile)) ); } private static Path resolveInstallLockFile(String value) { if (value == null || value.isBlank()) { return null; } try { return Path.of(value).toAbsolutePath().normalize(); } catch (InvalidPathException ignored) { return null; } } }