본문 바로가기

Android

Ktor Client 파일 쿠키 저장소 구현

반응형

다음 게시글에서 발전시켜, 쿠키 중복 저장을 줄일 수 있는 방법을 고민해보았습니다.

https://youtrack.jetbrains.com/issue/KTOR-2579

 

Persistent Client HttpCache : KTOR-2579

Currently the HttpCache is implemented as in-memory only. Accordingly using it in an iOS/Android multiplatform app, cache entries are lost when closing the app. It would be nice to have a file-based persistent cache like OkHttp (https://square.github.io/ok

youtrack.jetbrains.com

Ktor Client, Dagger Hilt를 사용하였습니다.

@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {
    @Provides
    @Singleton
    fun providesHttpClient(fileCookieStorage: FileCookieStorage) = HttpClient(OkHttp) {
        install(HttpCookies) {
            storage = fileCookieStorage
        }
        // ...
    }
}
@Singleton
class FileCookieStorage @Inject constructor(@ApplicationContext context: Context) : CookiesStorage {

    private val file = File(context.filesDir, "cookie.txt")
    private val cookies = mutableMapOf<String, String>()

    init {
        // 파일이 존재하지 않는 경우 생성
        if (!file.exists()) {
            file.createNewFile()
        }
        // 파일에서 맵으로 복원
        file.readLines().forEach {
            val (name, value) = it.split(":")
            cookies[name] = value
        }
    }

    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        if (requestUrl.isImportant()) {
            // 쿠키 메모리 갱신
            cookies[cookie.name] = cookie.value
            // 쿠키 파일 갱신
            cookies.map { "${it.key}:${it.value}" }
                .joinToString("\n")
                .also { file.writeText(it) }
        }
    }

    override fun close() = Unit

    override suspend fun get(requestUrl: Url): List<Cookie> {
        // 인코딩 기본 옵션을 사용하는 경우 퍼센트 인코딩 되어 쿠키 값이 다름
        return cookies.map { Cookie(it.key, it.value, encoding = CookieEncoding.RAW) }
            .takeIf { requestUrl.isImportant() }
            ?: emptyList()
    }

    private fun Url.isImportant(): Boolean {
        return host == CONST_URL // 호스트 하나의 쿠키만 저장하는 경우
        // return true // 전체 저장
        // return host in listOf(...) // 여러 호스트의 쿠키를 저장하는 경우, 이 경우 cookies를 더블 해시 맵으로 변경
    }
}
반응형