단방향 데이터 흐름을 만드는 이유에는 데이터 흐름을 파악하기 쉽게 하려는 목적도 있다.

콜백함수를 사용하게 되면 return이 존재하지 않아 결과를 처리하는 과정을 파악하기 위해 콜백 함수가 정의된 부분을 읽으러 이동해야 한다.

하지만 외부 라이브러리의 경우 Callback 함수를 parameter로 받는 경우가 있어 어쩔 수 없이 콜백을 사용해야 하는 경우가 생긴다.

이럴 때 suspendCancellableCoroutine을 사용해서 return을 받을 수 있다. 만약 1회성이 아니라 지속적으로 콜백을 받아야 하는 경우에는 callbackFlow를 통해 Flow<T>를 반환받아서 처리할 수 있다.

네이버 로그인의 경우 로그인 성공 여부를 callback을 통해서 받을 수 있었는데 result를 반환받기 위해서 suspendCancellableCoroutine을 사용했다.

@ExperimentalCoroutinesApi
class LoginDataSource(
    private val naverLoginService: NaverLoginService,
) {
    suspend fun authenticateWithNaver(
        context: Context,
    ): Result<SuccessOrFailure> {
        val result = suspendCancellableCoroutine { continuation ->
            val callback = object : OAuthLoginCallback {

                override fun onSuccess() {
                    continuation.resume(Result.success(SuccessOrFailure.Success), null)
                }

                override fun onFailure(httpStatus: Int, message: String) {
                    val errorCode = NaverIdLoginSDK.getLastErrorCode().code
                    val errorDescription = NaverIdLoginSDK.getLastErrorDescription()
                    if (BuildConfig.DEBUG) {
                        Log.d("에러", errorCode)
                        Log.d("에러", errorDescription.toString())
                    }
                    continuation.resume(
                        Result.failure(
                            Exception(errorDescription ?: "unknown error"),
                        ),
                        null,
                    )
                }

                override fun onError(errorCode: Int, message: String) {
                    onFailure(errorCode, message)
                }
            }

            NaverIdLoginSDK.authenticate(context, callback)
        }

        return result
    }