From 69648e5445e29877ab2454125b8f79d05e8c00a3 Mon Sep 17 00:00:00 2001 From: BeomBeom2 Date: Sun, 19 Apr 2026 15:58:46 +0900 Subject: [PATCH] =?UTF-8?q?[Refactor]=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=8B=9C,=20api=20=ED=81=B4=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EC=96=B8=ED=8A=B8=20=EC=9E=AC=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composeApp/build.gradle.kts | 1 + .../com/kus/kustaurant/KusApplication.kt | 12 +++- .../kotlin/com/kus/kustaurant/App.kt | 2 + .../kotlin/com/kus/kustaurant/di/initKoin.kt | 4 +- .../kus/kustaurant/navigation/MainScreen.kt | 45 ++++++------ .../com/kus/kustaurant/MainViewController.kt | 4 ++ settings.gradle.kts | 1 + shared/core/config/build.gradle.kts | 2 +- shared/core/startup/.gitignore | 1 + shared/core/startup/build.gradle.kts | 70 +++++++++++++++++++ .../core/startup/ExampleInstrumentedTest.kt | 24 +++++++ .../com/kus/core/startup/ExampleUnitTest.kt | 16 +++++ .../src/androidMain/AndroidManifest.xml | 4 ++ .../kotlin/com/kus/core/di/startupModule.kt | 13 ++++ .../com/kus/core/startup/AppInitializer.kt | 29 ++++++++ .../kotlin/com/kus/data/auth/api/Authpi.kt | 5 +- .../com/kus/data/auth/di/authDataModule.kt | 2 +- .../kus/data/community/api/CommunityApi.kt | 6 +- .../kus/kustaurant/detail/api/DetailApi.kt | 6 +- .../kotlin/com/kus/data/draw/api/DrawApi.kt | 6 +- .../kustaurant/evaluate/api/EvaluateApi.kt | 6 +- .../com/kus/kustaurant/home/api/HomeApi.kt | 8 ++- .../kotlin/com/kus/data/my/api/MyApi.kt | 6 +- .../com/kus/data/my/api/MyCommunityApi.kt | 6 +- .../com/kus/data/my/api/MyRestaurantApi.kt | 6 +- .../com/kus/data/network/ApiClientProvider.kt | 30 ++++++++ ...piHttpClient.kt => createApiHttpClient.kt} | 4 +- .../com/kus/data/network/di/networkModule.kt | 14 ++-- .../kus/shared/data/search/api/SearchApi.kt | 6 +- .../com/kus/shared/data/tier/api/TierApi.kt | 8 ++- .../kus/domain/auth/di/authDomainModule.kt | 1 - .../kus/domain/auth/session/SessionEvent.kt | 1 + .../kus/domain/auth/usecase/LogoutUseCase.kt | 4 ++ 33 files changed, 293 insertions(+), 60 deletions(-) create mode 100644 shared/core/startup/.gitignore create mode 100644 shared/core/startup/build.gradle.kts create mode 100644 shared/core/startup/src/androidDeviceTest/kotlin/com/kus/core/startup/ExampleInstrumentedTest.kt create mode 100644 shared/core/startup/src/androidHostTest/kotlin/com/kus/core/startup/ExampleUnitTest.kt create mode 100644 shared/core/startup/src/androidMain/AndroidManifest.xml create mode 100644 shared/core/startup/src/commonMain/kotlin/com/kus/core/di/startupModule.kt create mode 100644 shared/core/startup/src/commonMain/kotlin/com/kus/core/startup/AppInitializer.kt create mode 100644 shared/data/network/src/commonMain/kotlin/com/kus/data/network/ApiClientProvider.kt rename shared/data/network/src/commonMain/kotlin/com/kus/data/network/{creatApiHttpClient.kt => createApiHttpClient.kt} (98%) diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index cd9b043a..0d5184e4 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -60,6 +60,7 @@ kotlin { implementation(project(":shared:core:config")) implementation(project(":shared:core:logging")) implementation(project(":shared:core:serialization")) + implementation(project(":shared:core:startup")) implementation(project(":shared:data:network")) implementation(project(":shared:data:firstLaunch")) diff --git a/composeApp/src/androidMain/kotlin/com/kus/kustaurant/KusApplication.kt b/composeApp/src/androidMain/kotlin/com/kus/kustaurant/KusApplication.kt index ee6d4d86..ba362713 100644 --- a/composeApp/src/androidMain/kotlin/com/kus/kustaurant/KusApplication.kt +++ b/composeApp/src/androidMain/kotlin/com/kus/kustaurant/KusApplication.kt @@ -2,6 +2,7 @@ package com.kus.kustaurant import android.app.Application import com.kus.core.config.BuildKonfig +import com.kus.core.startup.AppInitializer import com.kus.data.auth.di.androidDataAuthModule import com.kus.data.community.di.androidDataCommunityModule import com.kus.data.firstLaunch.di.androidFirstLaunchModule @@ -13,21 +14,23 @@ import com.navercorp.nid.NidOAuth import com.navercorp.nid.core.data.datastore.NidOAuthInitializingCallback import di.androidTierMapPlatformModule import org.koin.android.ext.koin.androidContext +import org.koin.mp.KoinPlatform class KusApplication : Application() { + override fun onCreate() { super.onCreate() initLogger() NaverMapSdk.getInstance(this).client = NaverMapSdk.NaverCloudPlatformClient(BuildKonfig.NAVER_MAP_CLIENT_ID) - + NidOAuth.initialize( context = this, clientId = BuildKonfig.NAVER_CLIENT_ID, clientSecret = BuildKonfig.NAVER_CLIENT_SECRET, clientName = getString(R.string.app_name), callback = object : NidOAuthInitializingCallback { - override fun onSuccess() { } + override fun onSuccess() {} override fun onFailure(e: Exception) {} } ) @@ -39,7 +42,10 @@ class KusApplication : Application() { androidDataAuthModule, androidTierMapPlatformModule, androidFeatureCommunityModule, - androidDataCommunityModule) + androidDataCommunityModule + ) ) + + KoinPlatform.getKoin().get().initialize() } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/App.kt b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/App.kt index 6a8e0c4a..875dc7fd 100644 --- a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/App.kt +++ b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/App.kt @@ -102,6 +102,8 @@ fun SetNavigation( SessionEvent.LoginRequired -> { showRequireLoginPopup = true } + + else -> {} } } } diff --git a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/di/initKoin.kt b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/di/initKoin.kt index c234bd09..32560686 100644 --- a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/di/initKoin.kt +++ b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/di/initKoin.kt @@ -1,6 +1,7 @@ package com.kus.kustaurant.di import com.kus.core.config.di.configModule +import com.kus.core.di.startupModule import com.kus.data.auth.di.authDataModule import com.kus.data.community.di.communityDataModule import com.kus.data.draw.di.drawDataModule @@ -41,13 +42,14 @@ import org.koin.dsl.KoinAppDeclaration fun initKoin( config: KoinAppDeclaration? = null, additionalModules: List = emptyList(), -) : KoinApplication { +): KoinApplication { return startKoin { config?.invoke(this) modules( //core configModule, + startupModule, // domain firstLaunchDomainModule, diff --git a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/navigation/MainScreen.kt b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/navigation/MainScreen.kt index a73faafc..f80e1527 100644 --- a/composeApp/src/commonMain/kotlin/com/kus/kustaurant/navigation/MainScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/kus/kustaurant/navigation/MainScreen.kt @@ -32,7 +32,7 @@ import com.kus.feature.community.navigation.Community import com.kus.feature.community.navigation.CommunityDetail import com.kus.feature.community.navigation.CommunityWrite import com.kus.feature.community.navigation.communityMainNavGraph -import com.kus.feature.detail.navigation.Detail +import com.kus.feature.detail.navigation.navigateToDetail import com.kus.feature.draw.navigation.Draw import com.kus.feature.draw.navigation.drawNavGraph import com.kus.feature.home.navigation.Home @@ -55,7 +55,6 @@ import com.kus.feature.tier.navigation.Tier import com.kus.feature.tier.navigation.TierCategorySelect import com.kus.feature.tier.navigation.tierMainNavGraph import com.kus.feature.tier.ui.TierFilterState -import com.kus.feature.detail.navigation.navigateToDetail import com.kus.shared.domain.model.tier.filter.Cuisine import com.kus.feature.tier.TierKeys as TierResultKeys @@ -151,11 +150,11 @@ fun MainScreen( contentWindowInsets = WindowInsets.statusBars, containerColor = KusTheme.colors.c_FFFFFF, bottomBar = { - KusBottomBar( - modifier = Modifier.zIndex(2f), - selectedKey = selectedKey, - onNavigateToTab = { key -> mainNavController.navigateToTab(key) }, - ) + KusBottomBar( + modifier = Modifier.zIndex(2f), + selectedKey = selectedKey, + onNavigateToTab = { key -> mainNavController.navigateToTab(key) }, + ) }, ) { padding -> NavHost( @@ -163,31 +162,31 @@ fun MainScreen( startDestination = Home, enterTransition = { fadeIn(animationSpec = tween(durationMillis)) + - scaleIn( - initialScale = 0.98f, - animationSpec = tween(durationMillis) - ) + scaleIn( + initialScale = 0.98f, + animationSpec = tween(durationMillis) + ) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis)) + - scaleOut( - targetScale = 0.98f, - animationSpec = tween(durationMillis) - ) + scaleOut( + targetScale = 0.98f, + animationSpec = tween(durationMillis) + ) }, popEnterTransition = { fadeIn(animationSpec = tween(durationMillis)) + - scaleIn( - initialScale = 0.98f, - animationSpec = tween(durationMillis) - ) + scaleIn( + initialScale = 0.98f, + animationSpec = tween(durationMillis) + ) }, popExitTransition = { fadeOut(animationSpec = tween(durationMillis)) + - scaleOut( - targetScale = 0.98f, - animationSpec = tween(durationMillis) - ) + scaleOut( + targetScale = 0.98f, + animationSpec = tween(durationMillis) + ) }, modifier = Modifier .fillMaxSize() diff --git a/composeApp/src/iosMain/kotlin/com/kus/kustaurant/MainViewController.kt b/composeApp/src/iosMain/kotlin/com/kus/kustaurant/MainViewController.kt index c99baf4d..a4756f4b 100644 --- a/composeApp/src/iosMain/kotlin/com/kus/kustaurant/MainViewController.kt +++ b/composeApp/src/iosMain/kotlin/com/kus/kustaurant/MainViewController.kt @@ -9,11 +9,13 @@ import androidx.compose.ui.window.ComposeUIViewController import com.kus.appkit.di.iosAuthModule import com.kus.appkit.di.iosCommunityModule import com.kus.appkit.di.iosTierMapPlatformModule +import com.kus.core.startup.AppInitializer import com.kus.data.auth.di.iosAuthLocalModule import com.kus.data.firstLaunch.di.iosFirstLaunchModule import com.kus.kustaurant.di.initKoin import com.kus.logging.initLogger import org.koin.core.KoinApplication +import org.koin.mp.KoinPlatform private var koinStarted = false private var koinApp: KoinApplication? = null @@ -34,6 +36,8 @@ fun MainViewController() = ComposeUIViewController { koinStarted = true } + KoinPlatform.getKoin().get().initialize() + val koin = koinApp!!.koin //resolveOrLog(koin, PostNaverLoginUseCase::class) diff --git a/settings.gradle.kts b/settings.gradle.kts index f41202f0..15e26e3b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,6 +46,7 @@ include( ":shared:core:config", ":shared:core:serialization", ":shared:core:presentation", + ":shared:core:startup", ) include( diff --git a/shared/core/config/build.gradle.kts b/shared/core/config/build.gradle.kts index 41fae232..5b45f305 100644 --- a/shared/core/config/build.gradle.kts +++ b/shared/core/config/build.gradle.kts @@ -48,7 +48,7 @@ extensions.configure("buildkonfig") { buildConfigField( Type.STRING, "NAVER_CLIENT_SECRET", - resolveKey("NAVER_CLIENT_SECRET", required = true) // 가능하면 서버로 빼는 게 원칙 + resolveKey("NAVER_CLIENT_SECRET", required = true) ) buildConfigField( diff --git a/shared/core/startup/.gitignore b/shared/core/startup/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/shared/core/startup/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/shared/core/startup/build.gradle.kts b/shared/core/startup/build.gradle.kts new file mode 100644 index 00000000..a2282ea1 --- /dev/null +++ b/shared/core/startup/build.gradle.kts @@ -0,0 +1,70 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.androidLibrary) + alias(libs.plugins.composeMultiplatform) + alias(libs.plugins.composeCompiler) +} + +kotlin { + androidTarget() + + val xcfName = "shared:core:startupKit" + + iosX64 { + binaries.framework { + baseName = xcfName + } + } + + iosArm64 { + binaries.framework { + baseName = xcfName + } + } + + iosSimulatorArm64 { + binaries.framework { + baseName = xcfName + } + } + + + jvm("desktop") + + sourceSets { + commonMain { + dependencies { + implementation(libs.kotlinx.coroutines.core) + implementation(libs.koin.compose) + implementation(project(":shared:domain:auth")) + implementation(project(":shared:data:network")) + } + } + + commonTest { + dependencies { + implementation(libs.kotlin.test) + } + } + + androidMain { + dependencies { + } + } + + iosMain { + dependencies { + } + } + } +} + +android { + namespace = "com.kus.core.startup" + + compileSdk = libs.versions.android.compileSdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.android.minSdk.get().toInt() + } +} \ No newline at end of file diff --git a/shared/core/startup/src/androidDeviceTest/kotlin/com/kus/core/startup/ExampleInstrumentedTest.kt b/shared/core/startup/src/androidDeviceTest/kotlin/com/kus/core/startup/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..3e5b400a --- /dev/null +++ b/shared/core/startup/src/androidDeviceTest/kotlin/com/kus/core/startup/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.kus.core.startup + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.kus.core.startup.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/shared/core/startup/src/androidHostTest/kotlin/com/kus/core/startup/ExampleUnitTest.kt b/shared/core/startup/src/androidHostTest/kotlin/com/kus/core/startup/ExampleUnitTest.kt new file mode 100644 index 00000000..05a8eb18 --- /dev/null +++ b/shared/core/startup/src/androidHostTest/kotlin/com/kus/core/startup/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.kus.core.startup + +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/shared/core/startup/src/androidMain/AndroidManifest.xml b/shared/core/startup/src/androidMain/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/shared/core/startup/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/shared/core/startup/src/commonMain/kotlin/com/kus/core/di/startupModule.kt b/shared/core/startup/src/commonMain/kotlin/com/kus/core/di/startupModule.kt new file mode 100644 index 00000000..2ccf7825 --- /dev/null +++ b/shared/core/startup/src/commonMain/kotlin/com/kus/core/di/startupModule.kt @@ -0,0 +1,13 @@ +package com.kus.core.di + +import com.kus.core.startup.AppInitializer +import org.koin.dsl.module + +val startupModule = module { + single { + AppInitializer( + sessionBus = get(), + apiClientProvider = get(), + ) + } +} \ No newline at end of file diff --git a/shared/core/startup/src/commonMain/kotlin/com/kus/core/startup/AppInitializer.kt b/shared/core/startup/src/commonMain/kotlin/com/kus/core/startup/AppInitializer.kt new file mode 100644 index 00000000..fcc9cebe --- /dev/null +++ b/shared/core/startup/src/commonMain/kotlin/com/kus/core/startup/AppInitializer.kt @@ -0,0 +1,29 @@ +package com.kus.core.startup + +import com.kus.data.network.ApiClientProvider +import com.kus.domain.auth.session.SessionEvent +import com.kus.domain.auth.session.SessionEventBus +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch + +class AppInitializer( + private val sessionBus: SessionEventBus, + private val apiClientProvider: ApiClientProvider, +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) + + fun initialize() { + scope.launch { + sessionBus.events.collect { event -> + when (event) { + SessionEvent.LoggedOut -> { + apiClientProvider.reset() + } + else -> {} + } + } + } + } +} \ No newline at end of file diff --git a/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/api/Authpi.kt b/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/api/Authpi.kt index b58fba18..1093a71a 100644 --- a/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/api/Authpi.kt +++ b/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/api/Authpi.kt @@ -2,6 +2,7 @@ package com.kus.data.auth.api import com.kus.data.auth.remote.request.NaverLoginRequest import com.kus.data.auth.remote.response.LoginResponse +import com.kus.data.network.ApiClientProvider import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* @@ -9,9 +10,11 @@ import io.ktor.http.* class AuthApi( private val basicClient: HttpClient, - private val apiClient: HttpClient, + private val apiClientProvider: ApiClientProvider, private val baseUrl: String, ) { + private val apiClient get() = apiClientProvider.client + suspend fun postNaverLogin(request: NaverLoginRequest): LoginResponse { return basicClient.post("$baseUrl/api/v2/login/naver") { contentType(ContentType.Application.Json) diff --git a/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/di/authDataModule.kt b/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/di/authDataModule.kt index 29f01460..420082ce 100644 --- a/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/di/authDataModule.kt +++ b/shared/data/auth/src/commonMain/kotlin/com/kus/data/auth/di/authDataModule.kt @@ -26,7 +26,7 @@ val authDataModule = module { single { AuthApi( basicClient = get(named("basicClient")), - apiClient = get(named("apiClient")), + apiClientProvider = get(), baseUrl = get(named("BASE_URL")) ) } diff --git a/shared/data/community/src/commonMain/kotlin/com/kus/data/community/api/CommunityApi.kt b/shared/data/community/src/commonMain/kotlin/com/kus/data/community/api/CommunityApi.kt index 731720ea..a227f3fa 100644 --- a/shared/data/community/src/commonMain/kotlin/com/kus/data/community/api/CommunityApi.kt +++ b/shared/data/community/src/commonMain/kotlin/com/kus/data/community/api/CommunityApi.kt @@ -12,8 +12,8 @@ import com.kus.data.community.remote.response.CommunityPostScrapResponse import com.kus.data.community.remote.response.CommunityPostUploadImageResponse import com.kus.data.community.remote.response.CommunityRankingResponse import com.kus.data.community.remote.response.PostResponse +import com.kus.data.network.ApiClientProvider import com.kus.domain.community.model.AuthUserInfo -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete import io.ktor.client.request.forms.formData @@ -33,8 +33,10 @@ import io.ktor.http.contentType import io.ktor.http.isSuccess class CommunityApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getCommunityPostDetailData( postId: Long, deviceId: String? diff --git a/shared/data/detail/src/commonMain/kotlin/com/kus/kustaurant/detail/api/DetailApi.kt b/shared/data/detail/src/commonMain/kotlin/com/kus/kustaurant/detail/api/DetailApi.kt index 6f18cd57..46c3ff0b 100644 --- a/shared/data/detail/src/commonMain/kotlin/com/kus/kustaurant/detail/api/DetailApi.kt +++ b/shared/data/detail/src/commonMain/kotlin/com/kus/kustaurant/detail/api/DetailApi.kt @@ -1,5 +1,6 @@ package com.kus.kustaurant.detail.api +import com.kus.data.network.ApiClientProvider import com.kus.kustaurant.detail.remote.response.CommentReactionResponse import com.kus.kustaurant.detail.remote.response.DetailResponse import com.kus.kustaurant.detail.remote.response.EvaluationReactionResponse @@ -7,7 +8,6 @@ import com.kus.kustaurant.detail.remote.response.FavoriteResponse import com.kus.kustaurant.detail.remote.response.ReviewCommentResponse import com.kus.kustaurant.detail.remote.response.ReviewResponse import com.kus.kustaurant.detail.remote.request.PostCommentRequest -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete import io.ktor.client.request.get @@ -19,8 +19,10 @@ import io.ktor.http.ContentType import io.ktor.http.contentType class DetailApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getRestaurantDetail(restaurantId: Long): DetailResponse { return client.get("/api/v2/restaurants/$restaurantId").body() } diff --git a/shared/data/draw/src/commonMain/kotlin/com/kus/data/draw/api/DrawApi.kt b/shared/data/draw/src/commonMain/kotlin/com/kus/data/draw/api/DrawApi.kt index 6d5b048f..f90bd4c9 100644 --- a/shared/data/draw/src/commonMain/kotlin/com/kus/data/draw/api/DrawApi.kt +++ b/shared/data/draw/src/commonMain/kotlin/com/kus/data/draw/api/DrawApi.kt @@ -1,14 +1,16 @@ package com.kus.data.draw.api import com.kus.data.draw.remote.DrawRestaurantResponse -import io.ktor.client.HttpClient +import com.kus.data.network.ApiClientProvider import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.parameter class DrawApi( - private val client : HttpClient + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getDrawRestaurantList( cuisines: String, locations: String, diff --git a/shared/data/evaluate/src/commonMain/kotlin/com/kus/kustaurant/evaluate/api/EvaluateApi.kt b/shared/data/evaluate/src/commonMain/kotlin/com/kus/kustaurant/evaluate/api/EvaluateApi.kt index a9a9f9cb..90f90870 100644 --- a/shared/data/evaluate/src/commonMain/kotlin/com/kus/kustaurant/evaluate/api/EvaluateApi.kt +++ b/shared/data/evaluate/src/commonMain/kotlin/com/kus/kustaurant/evaluate/api/EvaluateApi.kt @@ -1,8 +1,8 @@ package com.kus.kustaurant.evaluate.api +import com.kus.data.network.ApiClientProvider import com.kus.kustaurant.evaluate.remote.request.EvaluationRequest import com.kus.kustaurant.evaluate.remote.response.EvaluationResponse -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.forms.formData @@ -13,8 +13,10 @@ import io.ktor.http.Headers import io.ktor.http.HttpHeaders class EvaluateApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getEvaluation(restaurantId: Long): EvaluationResponse { return client.get("/api/v2/auth/restaurants/$restaurantId/evaluation").body() } diff --git a/shared/data/home/src/commonMain/kotlin/com/kus/kustaurant/home/api/HomeApi.kt b/shared/data/home/src/commonMain/kotlin/com/kus/kustaurant/home/api/HomeApi.kt index 2f0f5fdc..c1a32f67 100644 --- a/shared/data/home/src/commonMain/kotlin/com/kus/kustaurant/home/api/HomeApi.kt +++ b/shared/data/home/src/commonMain/kotlin/com/kus/kustaurant/home/api/HomeApi.kt @@ -1,14 +1,16 @@ package com.kus.kustaurant.home.api +import com.kus.data.network.ApiClientProvider import com.kus.kustaurant.home.remote.response.HomeInfoResponse -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get class HomeApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { - suspend fun getHomeInfo() : HomeInfoResponse { + private val client get() = apiClientProvider.client + + suspend fun getHomeInfo(): HomeInfoResponse { return client.get("/api/v2/home").body() } } diff --git a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyApi.kt b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyApi.kt index c043342c..0663d669 100644 --- a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyApi.kt +++ b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyApi.kt @@ -4,7 +4,7 @@ import com.kus.data.my.remote.response.MyInfoResponse import com.kus.data.my.remote.response.PatchProfileResponse import com.kus.data.my.remote.response.request.FeedbackRequest import com.kus.data.my.remote.response.request.PatchProfileInfoRequest -import io.ktor.client.HttpClient +import com.kus.data.network.ApiClientProvider import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.patch @@ -14,8 +14,10 @@ import io.ktor.http.ContentType import io.ktor.http.contentType class MyApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getMyInfo(): MyInfoResponse { return client.get("/api/v2/mypage").body() } diff --git a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyCommunityApi.kt b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyCommunityApi.kt index be596e84..f3108736 100644 --- a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyCommunityApi.kt +++ b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyCommunityApi.kt @@ -2,13 +2,15 @@ package com.kus.data.my.api import com.kus.data.my.remote.response.MyCommentResponse import com.kus.data.my.remote.response.MyPostResponse -import io.ktor.client.HttpClient +import com.kus.data.network.ApiClientProvider import io.ktor.client.call.body import io.ktor.client.request.get class MyCommunityApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getMyCommunityComments(): List { return client.get("/api/v2/auth/mypage/community/comments").body() } diff --git a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyRestaurantApi.kt b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyRestaurantApi.kt index c8d6be67..010c330b 100644 --- a/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyRestaurantApi.kt +++ b/shared/data/my/src/commonMain/kotlin/com/kus/data/my/api/MyRestaurantApi.kt @@ -2,13 +2,15 @@ package com.kus.data.my.api import com.kus.data.my.remote.response.EvaluatedResponse import com.kus.data.my.remote.response.FavoriteResponse -import io.ktor.client.HttpClient +import com.kus.data.network.ApiClientProvider import io.ktor.client.call.body import io.ktor.client.request.get class MyRestaurantApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getFavoriteRes(): List { return client.get("/api/v2/auth/mypage/restaurants/favorite").body() } diff --git a/shared/data/network/src/commonMain/kotlin/com/kus/data/network/ApiClientProvider.kt b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/ApiClientProvider.kt new file mode 100644 index 00000000..f11b45a5 --- /dev/null +++ b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/ApiClientProvider.kt @@ -0,0 +1,30 @@ +package com.kus.data.network + +import com.kus.data.network.auth.TokenManager +import com.kus.domain.auth.session.SessionEventEmitter +import io.ktor.client.HttpClient +import io.ktor.client.engine.HttpClientEngine + +class ApiClientProvider( + private val engine: HttpClientEngine, + private val tokenManager: TokenManager, + private val sessionEvents: SessionEventEmitter, + private val baseUrl: String, + private val isDebug: Boolean = true, +) { + private var _client: HttpClient = createClient() + val client: HttpClient get() = _client + + fun reset() { + _client.close() + _client = createClient() + } + + private fun createClient() = createApiHttpClient( + engine = engine, + tokenManager = tokenManager, + sessionEvents = sessionEvents, + baseUrl = baseUrl, + isDebug = isDebug, + ) +} \ No newline at end of file diff --git a/shared/data/network/src/commonMain/kotlin/com/kus/data/network/creatApiHttpClient.kt b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/createApiHttpClient.kt similarity index 98% rename from shared/data/network/src/commonMain/kotlin/com/kus/data/network/creatApiHttpClient.kt rename to shared/data/network/src/commonMain/kotlin/com/kus/data/network/createApiHttpClient.kt index ec372dd7..eae17ea1 100644 --- a/shared/data/network/src/commonMain/kotlin/com/kus/data/network/creatApiHttpClient.kt +++ b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/createApiHttpClient.kt @@ -24,7 +24,7 @@ import io.ktor.http.takeFrom import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json -fun creatApiHttpClient( +fun createApiHttpClient( engine: HttpClientEngine, tokenManager: TokenManager, isDebug: Boolean = true, @@ -38,7 +38,7 @@ fun creatApiHttpClient( expectSuccess = false if (isDebug) { - install(Logging) { logger = Logger.SIMPLE; level = LogLevel.BODY } + install(Logging) { logger = Logger.SIMPLE; level = LogLevel.ALL } } install(ContentNegotiation) { diff --git a/shared/data/network/src/commonMain/kotlin/com/kus/data/network/di/networkModule.kt b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/di/networkModule.kt index a96c3147..2e5371ae 100644 --- a/shared/data/network/src/commonMain/kotlin/com/kus/data/network/di/networkModule.kt +++ b/shared/data/network/src/commonMain/kotlin/com/kus/data/network/di/networkModule.kt @@ -1,6 +1,6 @@ package com.kus.data.network.di -import com.kus.data.network.creatApiHttpClient +import com.kus.data.network.ApiClientProvider import com.kus.data.network.createBasicHttpClient import com.kus.data.network.provideEngine import io.ktor.client.HttpClient @@ -15,8 +15,8 @@ val networkModule = module { ) } - single(named("apiClient")) { - creatApiHttpClient( + single { + ApiClientProvider( engine = provideEngine(), tokenManager = get(), sessionEvents = get(), @@ -25,5 +25,9 @@ val networkModule = module { ) } - single { get(named("apiClient")) } -} + factory(named("apiClient")) { + get().client + } + + factory { get(named("apiClient")) } +} \ No newline at end of file diff --git a/shared/data/search/src/commonMain/kotlin/com/kus/shared/data/search/api/SearchApi.kt b/shared/data/search/src/commonMain/kotlin/com/kus/shared/data/search/api/SearchApi.kt index f53a0881..55c86921 100644 --- a/shared/data/search/src/commonMain/kotlin/com/kus/shared/data/search/api/SearchApi.kt +++ b/shared/data/search/src/commonMain/kotlin/com/kus/shared/data/search/api/SearchApi.kt @@ -1,14 +1,16 @@ package com.kus.shared.data.search.api +import com.kus.data.network.ApiClientProvider import com.kus.shared.data.search.remote.response.SearchResultResponse -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.parameter class SearchApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getSearchResult( searchTerm: String, page: Int, diff --git a/shared/data/tier/src/commonMain/kotlin/com/kus/shared/data/tier/api/TierApi.kt b/shared/data/tier/src/commonMain/kotlin/com/kus/shared/data/tier/api/TierApi.kt index 91550dbf..436b27d4 100644 --- a/shared/data/tier/src/commonMain/kotlin/com/kus/shared/data/tier/api/TierApi.kt +++ b/shared/data/tier/src/commonMain/kotlin/com/kus/shared/data/tier/api/TierApi.kt @@ -1,21 +1,23 @@ package com.kus.shared.data.tier.api +import com.kus.data.network.ApiClientProvider import com.kus.shared.data.tier.remote.response.TierListResponse import com.kus.shared.data.tier.remote.response.TierMapDataResponse -import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.parameter class TierApi( - private val client: HttpClient, + private val apiClientProvider: ApiClientProvider, ) { + private val client get() = apiClientProvider.client + suspend fun getRestaurantList( cuisines: String, situations: String, locations: String, page: Int, - isAiTier : Boolean, + isAiTier: Boolean, limit: Int = 30, ): TierListResponse { return client.get("/api/v2/tier") { diff --git a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/di/authDomainModule.kt b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/di/authDomainModule.kt index 0a438504..b3d423e4 100644 --- a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/di/authDomainModule.kt +++ b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/di/authDomainModule.kt @@ -17,6 +17,5 @@ var authDomainModule = module { singleOf(::DeleteUserTokensUseCase) singleOf(::LogoutUseCase) singleOf(::GetSessionAvailabilityUseCase) - single { SessionEventBus() } singleOf(::SessionEventBus) bind SessionEventEmitter::class } \ No newline at end of file diff --git a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/session/SessionEvent.kt b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/session/SessionEvent.kt index 2a56573a..d18708a1 100644 --- a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/session/SessionEvent.kt +++ b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/session/SessionEvent.kt @@ -3,4 +3,5 @@ package com.kus.domain.auth.session sealed interface SessionEvent { data object Expired : SessionEvent data object LoginRequired : SessionEvent + data object LoggedOut : SessionEvent } \ No newline at end of file diff --git a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/LogoutUseCase.kt b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/LogoutUseCase.kt index af4ee00e..4cbcfa4b 100644 --- a/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/LogoutUseCase.kt +++ b/shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/LogoutUseCase.kt @@ -2,15 +2,19 @@ package com.kus.domain.auth.usecase import com.kus.domain.auth.repository.AuthRepository import com.kus.domain.auth.repository.AuthTokenStore +import com.kus.domain.auth.session.SessionEvent +import com.kus.domain.auth.session.SessionEventEmitter class LogoutUseCase( private val tokenStore: AuthTokenStore, private val repository: AuthRepository, + private val sessionEvents: SessionEventEmitter, ) { suspend operator fun invoke(): Boolean { repository.postLogout() .onSuccess { tokenStore.clear() + sessionEvents.emit(SessionEvent.LoggedOut) return true } return false