From d552584446c94207e0fb3805368d7d96f4a0029d Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Fri, 27 Mar 2026 18:03:06 +0900 Subject: [PATCH] ... --- src/main/kotlin/Defines.kt | 4 +-- src/main/kotlin/Main.kt | 17 +++++++--- src/main/kotlin/util/PortFinder.kt | 51 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/util/PortFinder.kt diff --git a/src/main/kotlin/Defines.kt b/src/main/kotlin/Defines.kt index 8cee376..4bc5c37 100644 --- a/src/main/kotlin/Defines.kt +++ b/src/main/kotlin/Defines.kt @@ -1,7 +1,7 @@ object Defines { val DETAILLOG = false - val LLM_PORT = 8080 - val EMBEDDING_PORT = 8081 + var LLM_PORT = 8080 + var EMBEDDING_PORT = 8081 val AUTOSELL = false val BLACKLISTEDSTOCKCODES = listOf() } \ No newline at end of file diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 4d406ce..fb5d130 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -54,6 +54,7 @@ import service.TradingDecisionCallback import ui.DashboardScreen import ui.SettingsScreen import ui.TradingDecisionLog +import util.PortFinder // 화면 상태 정의 enum class AppScreen { Settings, Dashboard, TradingDecision } @@ -94,13 +95,21 @@ fun initLogger(isDebug: Boolean) { println("🤫 운영 모드: 에러 로그만 출력합니다.") } } - +private var isAppStarted = false fun main() = application { - initLogger(DETAILLOG) + if (!isAppStarted) { + initLogger(DETAILLOG) + val (port1, port2) = PortFinder.findAvailablePortPair(18080) + + println("🚀 AI 서버용 포트 할당 완료: 메인($port1), 서브($port2)") + LLM_PORT = port1 + EMBEDDING_PORT = port2 + + isAppStarted = true + } + val trayState = rememberTrayState() var isWindowOpen by remember { mutableStateOf(false) } // 창의 표시 상태 관리 - - LaunchedEffect(Unit) { SystemSleepPreventer.start() AutoTradingManager.startBackgroundScheduler() diff --git a/src/main/kotlin/util/PortFinder.kt b/src/main/kotlin/util/PortFinder.kt new file mode 100644 index 0000000..9fa9c74 --- /dev/null +++ b/src/main/kotlin/util/PortFinder.kt @@ -0,0 +1,51 @@ +package util +import java.net.ServerSocket + +object PortFinder { + /** + * 사용 가능한 두 개의 포트를 찾아 Pair(첫번째, 두번째)로 반환합니다. + * @param startPort 검색을 시작할 포트 번호 + * @param mustBeConsecutive true일 경우 두 포트가 연속번호(ex: 18080, 18081)여야 함 + */ + fun findAvailablePortPair(startPort: Int, mustBeConsecutive: Boolean = true): Pair { + var currentPort = startPort + + while (currentPort < 65534) { + if (isPortAvailable(currentPort)) { + if (mustBeConsecutive) { + // 연속된 포트가 필요한 경우 (n, n+1) + if (isPortAvailable(currentPort + 1)) { + return Pair(currentPort, currentPort + 1) + } + } else { + // 연속될 필요 없는 경우, 그다음 사용 가능한 포트를 찾음 + val secondPort = findAvailablePort(currentPort + 1) + return Pair(currentPort, secondPort) + } + } + currentPort++ + } + throw RuntimeException("⚠️ 사용 가능한 포트 쌍을 찾을 수 없습니다.") + } + + /** + * 단일 포트 가용성 체크 (기존 로직 유지) + */ + fun findAvailablePort(startPort: Int): Int { + for (port in startPort..65535) { + if (isPortAvailable(port)) return port + } + throw RuntimeException("⚠️ 사용 가능한 포트가 없습니다.") + } + + private fun isPortAvailable(port: Int): Boolean { + return try { + ServerSocket(port).use { socket -> + socket.reuseAddress = true + true + } + } catch (e: Exception) { + false + } + } +} \ No newline at end of file