...
This commit is contained in:
parent
7fa1c36355
commit
c5bc3f9bf0
@ -20,6 +20,7 @@ dependencies {
|
|||||||
implementation(compose.desktop.currentOs)
|
implementation(compose.desktop.currentOs)
|
||||||
implementation(compose.material)
|
implementation(compose.material)
|
||||||
implementation(compose.materialIconsExtended)
|
implementation(compose.materialIconsExtended)
|
||||||
|
implementation("io.ktor:ktor-client-okhttp-jvm:2.3.11")
|
||||||
|
|
||||||
// Ktor (Network)
|
// Ktor (Network)
|
||||||
val ktorVersion = "2.3.11"
|
val ktorVersion = "2.3.11"
|
||||||
|
|||||||
@ -149,6 +149,7 @@ fun main() = application {
|
|||||||
CoroutineScope(Dispatchers.Default).launch {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
AutoTradingManager.startAutoDiscoveryLoop()
|
AutoTradingManager.startAutoDiscoveryLoop()
|
||||||
KisWebSocketManager.onExecutionReceived = AutoTradingManager.onExecutionReceived
|
KisWebSocketManager.onExecutionReceived = AutoTradingManager.onExecutionReceived
|
||||||
|
KisWebSocketManager.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.modelPath.isNotEmpty()) {
|
if (config.modelPath.isNotEmpty()) {
|
||||||
|
|||||||
@ -2,7 +2,14 @@ package network
|
|||||||
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.engine.cio.CIO
|
||||||
|
import io.ktor.client.engine.okhttp.OkHttp
|
||||||
|
import io.ktor.client.engine.config
|
||||||
|
import io.ktor.client.plugins.HttpTimeout
|
||||||
import io.ktor.client.plugins.websocket.*
|
import io.ktor.client.plugins.websocket.*
|
||||||
|
import io.ktor.client.engine.cio.*
|
||||||
|
import io.ktor.client.engine.okhttp.*
|
||||||
|
import io.ktor.client.plugins.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.websocket.*
|
import io.ktor.websocket.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@ -12,21 +19,55 @@ import kotlinx.serialization.json.jsonPrimitive
|
|||||||
import model.KisSession
|
import model.KisSession
|
||||||
import model.RealTimeTrade
|
import model.RealTimeTrade
|
||||||
import util.AesCrypto
|
import util.AesCrypto
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
object KisWebSocketManager {
|
object KisWebSocketManager {
|
||||||
private val client = HttpClient {
|
|
||||||
|
val os = System.getProperty("os.name").lowercase()
|
||||||
|
val arch = System.getProperty("os.arch").lowercase()
|
||||||
|
val isWin = os.contains("win")
|
||||||
|
|
||||||
|
private val client = HttpClient(if(isWin){ OkHttp } else { CIO }) {
|
||||||
install(WebSockets) {
|
install(WebSockets) {
|
||||||
pingInterval = 20_000 // 20초마다 표준 웹소켓 핑 전송 (서버-클라이언트 연결 유지 도움)
|
pingInterval = 20_000
|
||||||
|
}
|
||||||
|
install(HttpTimeout) {
|
||||||
|
requestTimeoutMillis = 30_000 // 전체 요청 시간
|
||||||
|
connectTimeoutMillis = 10_000 // 서버 연결 시간
|
||||||
|
socketTimeoutMillis = 30_000 // 데이터 패킷 간격 시간
|
||||||
|
}
|
||||||
|
|
||||||
|
// 엔진별 상세 설정 (config 대신 해당 엔진 명칭 사용)
|
||||||
|
if (isWin) {
|
||||||
|
engine {
|
||||||
|
// OkHttp 환경 특화: 윈도우 네트워크 유휴 상태 방지
|
||||||
|
this as OkHttpConfig
|
||||||
|
config {
|
||||||
|
retryOnConnectionFailure(true)
|
||||||
|
connectTimeout(15, TimeUnit.SECONDS)
|
||||||
|
readTimeout(0, TimeUnit.SECONDS) // 무제한 대기
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
engine {
|
||||||
|
// CIO 엔진 설정
|
||||||
|
this as CIOEngineConfig
|
||||||
|
endpoint {
|
||||||
|
connectTimeout = 15_000
|
||||||
|
requestTimeout = 30_000
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var session: DefaultClientWebSocketSession? = null
|
private var session: DefaultClientWebSocketSession? = null
|
||||||
private val isConnected = AtomicBoolean(false)
|
private val isConnected = AtomicBoolean(false)
|
||||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
private var connectJob: Job? = null
|
private var connectJob: Job? = null
|
||||||
|
|
||||||
// 콜백 리스너
|
// 콜백 리스너
|
||||||
var onPriceUpdate: ((RealTimeTrade) -> Unit)? = null
|
var onPriceUpdate: ((RealTimeTrade) -> Unit)? = null
|
||||||
|
|
||||||
var onExecutionReceived: ((String, String, String, String, Boolean) -> Unit)? = null
|
var onExecutionReceived: ((String, String, String, String, Boolean) -> Unit)? = null
|
||||||
|
|
||||||
suspend fun connect() {
|
suspend fun connect() {
|
||||||
@ -72,7 +113,7 @@ object KisWebSocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// private val _currentPrice = mutableStateOf("0")
|
// private val _currentPrice = mutableStateOf("0")
|
||||||
private val currentPrice = androidx.compose.runtime.mutableStateMapOf<String, String>()
|
private val currentPrice = androidx.compose.runtime.mutableStateMapOf<String, String>()
|
||||||
// val currentPrice = _currentPrice
|
// val currentPrice = _currentPrice
|
||||||
|
|
||||||
|
|||||||
@ -164,15 +164,20 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
var retryCount = 0
|
var retryCount = 0
|
||||||
val maxRetries = 3
|
val maxRetries = 3
|
||||||
val retryDelay = 90_000L // 1분 30초
|
val totalDelaySeconds = 90 // 1분 30초 = 90초
|
||||||
var isAuthCompleted = false
|
var isAuthCompleted = false
|
||||||
|
|
||||||
while (retryCount <= maxRetries && !isAuthCompleted) {
|
while (retryCount <= maxRetries && !isAuthCompleted) {
|
||||||
|
// 재시도 시 대기 및 카운트다운 표시
|
||||||
if (retryCount > 0) {
|
if (retryCount > 0) {
|
||||||
statusMessage = "⏳ 인증 재시도 중... (${retryCount}/${maxRetries}) - 1분 30초 후 재시작"
|
for (secondsLeft in totalDelaySeconds downTo 1) {
|
||||||
delay(retryDelay)
|
statusMessage = "⚠️ 인증 실패. ${secondsLeft}초 후 자동으로 다시 시도합니다. (시도 ${retryCount}/${maxRetries})"
|
||||||
|
delay(1000L) // 1초 대기
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusMessage = if (retryCount == 0) "⏳ 인증 시도 중..." else "⏳ ${retryCount}차 재시도 중..."
|
||||||
|
|
||||||
// 1. 설정값 저장
|
// 1. 설정값 저장
|
||||||
KisSession.config = config
|
KisSession.config = config
|
||||||
DatabaseFactory.saveConfig(config)
|
DatabaseFactory.saveConfig(config)
|
||||||
@ -194,9 +199,8 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
retryCount++
|
retryCount++
|
||||||
if (retryCount > maxRetries) {
|
if (retryCount > maxRetries) {
|
||||||
statusMessage = "❌ 인증 실패. 3회 재시도 후 중단되었습니다. 키 정보를 확인하세요."
|
statusMessage = "❌ 인증 실패. 3회 재시도 후 중단되었습니다. 키 정보를 확인하세요."
|
||||||
} else {
|
|
||||||
statusMessage = "⚠️ 인증 실패. 잠시 후 자동으로 다시 시도합니다. (시도 $retryCount)"
|
|
||||||
}
|
}
|
||||||
|
// 다음 루프에서 카운트다운 진입
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user