Skip to content

Commit

Permalink
add remote repository and api for server [FoKE-Developers#35]
Browse files Browse the repository at this point in the history
- 서버 통신 기능 베이스코드 구현
- https://4cuts.store/docs
  • Loading branch information
DokySp committed Oct 9, 2024
1 parent bcaf285 commit c7d7598
Show file tree
Hide file tree
Showing 17 changed files with 324 additions and 7 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.foke.together.data.datasource.remote

import com.foke.together.data.datasource.remote.dto.AccountRegisterRequest
import com.foke.together.data.datasource.remote.dto.AccountRegisterResponse
import com.foke.together.data.datasource.remote.dto.AccountSigninResponse
import com.foke.together.data.datasource.remote.dto.AccountWhoAmIResponse
import com.foke.together.data.datasource.remote.dto.S3PresignedUrlResponse
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.HeaderMap
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Query
import retrofit2.http.Url

interface WebClientApi {
// account
@POST("api/account/register")
suspend fun accountRegister(
@Body body: AccountRegisterRequest
): Result<AccountRegisterResponse>

@GET("api/account/register")
suspend fun accountSignin(
@Query("email") email: String,
@Query("password") password: String
): Result<AccountSigninResponse>

@GET("api/account/who-am-i")
suspend fun accountWhoAmI(
@HeaderMap headers: HashMap<String, String>,
): Result<AccountWhoAmIResponse>

// s3
@GET("api/s3/presigned-url")
suspend fun s3PresignedUrl(
@HeaderMap headers: HashMap<String, String>,
@Query("key") key: String,
@Query("ContentLength") contentLength: String, // max: 20971520
): Result<S3PresignedUrlResponse>

@PUT
suspend fun sendFileToCloud(
@Url url: String,
@HeaderMap headers: HashMap<String, String>,
@Body body: RequestBody
): Result<ResponseBody>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.foke.together.data.datasource.remote

import com.foke.together.util.AppPolicy
import com.foke.together.util.retrofit.NetworkCallAdapterFactory
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object WebClientModule {

@Singleton
@Provides
@Named("okHttpWebClient")
fun provideOkHttpWebClient() = OkHttpClient.Builder()
.connectTimeout(AppPolicy.WEB_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(AppPolicy.WEB_READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(AppPolicy.WEB_WRITE_TIMEOUT, TimeUnit.SECONDS)
.build()

@Singleton
@Provides
@Named("webClientRetrofit")
fun provideWebClientRetrofit(
@Named("okHttpWebClient") okHttpClient: OkHttpClient
) = Retrofit.Builder()
.baseUrl(AppPolicy.WEB_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create(
GsonBuilder().setLenient().create()
))
.addCallAdapterFactory(NetworkCallAdapterFactory())
.client(okHttpClient)
.build()

@Singleton
@Provides
fun provideWebClientApi(
@Named("webClientRetrofit") retrofit: Retrofit
): WebClientApi =
retrofit.create(WebClientApi::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.foke.together.data.datasource.remote

import com.foke.together.data.datasource.remote.dto.AccountRegisterRequest
import com.foke.together.data.datasource.remote.dto.S3PresignedUrlResponse
import com.foke.together.util.AppPolicy
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody
import java.io.File
import javax.inject.Inject

class WebDataSource @Inject constructor(
private val webClientApi: WebClientApi,
) {
private val headers = HashMap<String, String>()

suspend fun accountWhoAmI() =
webClientApi.accountWhoAmI(headers)

suspend fun accountRegister(email: String, name: String, password: String) =
webClientApi.accountRegister(
AccountRegisterRequest(email, name, password)
)

suspend fun accountSignIn(email: String, password: String): Result<Unit> {
webClientApi.accountSignin(email, password)
.onSuccess {
setToken(it.token)
return Result.success(Unit)
}
.onFailure {
setToken("")
return Result.failure(it)
}
return Result.failure(Exception("unknown error"))
}

suspend fun s3PreSignedUrl(key: String, file: File): Result<S3PresignedUrlResponse> {
val contentLength = file.length()
if (contentLength > AppPolicy.WEB_FILE_MAX_CONTENT_LENGTH) {
return Result.failure(Exception("file size is over limit"))
}
return webClientApi.s3PresignedUrl(
headers = headers,
key = key,
contentLength = file.length().toString()
)
}

suspend fun sendFileToCloud(preSignedUrl: String, file: File): Result<ResponseBody> {
val requestBody = file.asRequestBody("application/octet-stream".toMediaType())
return webClientApi.sendFileToCloud(
url = preSignedUrl,
hashMapOf("Content-Type" to requestBody.contentType().toString()),
body = requestBody
)
}

private fun setToken(token: String) {
headers["token"] = token
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.data.datasource.remote.dto

data class AccountRegisterRequest(
val email: String, // max 32
val name: String, // max 32
val password: String // max 32
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.data.datasource.remote.dto

import com.google.gson.annotations.SerializedName

data class AccountRegisterResponse (
@SerializedName("token") val token: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.data.datasource.remote.dto

import com.google.gson.annotations.SerializedName

data class AccountSigninResponse (
@SerializedName("token") val token: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.foke.together.data.datasource.remote.dto

import com.google.gson.annotations.SerializedName

data class AccountWhoAmIResponse (
@SerializedName("name") val name: String,
@SerializedName("email") val email: String,
@SerializedName("id") val id: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.data.datasource.remote.dto

import com.google.gson.annotations.SerializedName

data class S3PresignedUrlResponse (
@SerializedName("presignedUrl") val presignedUrl: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.foke.together.external.network.interceptor

import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Response

class MockInterceptor: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
// TODO: make mock for test
return Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_2)
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.foke.together.data.repository

import com.foke.together.data.datasource.remote.WebDataSource
import com.foke.together.domain.interactor.entity.AccountData
import com.foke.together.domain.output.RemoteRepositoryInterface
import java.io.File
import javax.inject.Inject

class RemoteRepository @Inject constructor(
private val webDataSource: WebDataSource
) : RemoteRepositoryInterface {
override suspend fun registerAccount(data: AccountData): Result<Unit> {
return data.name?.let { name ->
webDataSource.accountRegister(data.email, name, data.password)
.onSuccess {
return Result.success(Unit)
}
.onFailure {
return Result.failure(it)
}
Result.failure(Exception("unknown error"))
} ?: Result.failure(Exception("name is null"))
}

override suspend fun signIn(data: AccountData): Result<Unit> =
webDataSource.accountSignIn(data.email, data.password)

override suspend fun getAccountStatus(): Result<AccountData> {
webDataSource.accountWhoAmI()
.onSuccess {
return Result.success(
AccountData(it.email, "", it.name)
)
}
.onFailure {
return Result.failure(it)
}
return Result.failure(Exception("unknown error"))
}

override suspend fun getUploadUrl(key: String, file: File): Result<String> {
webDataSource.s3PreSignedUrl(key, file)
.onSuccess {
return Result.success(it.presignedUrl)
}
.onFailure {
return Result.failure(it)
}
return Result.failure(Exception("unknown error"))
}

override suspend fun uploadFile(preSignedUrl: String, file: File): Result<Unit> {
webDataSource.sendFileToCloud(preSignedUrl, file)
.onSuccess {
return Result.success(Unit)
}
.onFailure {
return Result.failure(it)
}
return Result.failure(Exception("unknown error"))
}

companion object {
val TAG = RemoteRepository::class.java.simpleName
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.foke.together.data.repository.di

import com.foke.together.data.repository.AppPreferencesRepository
import com.foke.together.data.repository.RemoteRepository
import com.foke.together.domain.output.AppPreferenceInterface
import com.foke.together.domain.output.RemoteRepositoryInterface
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -12,4 +14,7 @@ import dagger.hilt.android.components.ViewModelComponent
abstract class RepositoryModule {
@Binds
abstract fun bindAppPreferenceRepository(appPreferenceRepository: AppPreferencesRepository): AppPreferenceInterface

@Binds
abstract fun bindRemoteRepository(remoteRepository: RemoteRepository): RemoteRepositoryInterface
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.domain.interactor.entity

data class AccountData (
val email: String,
val password: String,
val name: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.foke.together.domain.interactor.entity

data class PreSignedFileData (
val key: String,
val contentLength: Long,
val preSignedUrl: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.foke.together.domain.output

import com.foke.together.domain.interactor.entity.AccountData
import java.io.File

interface RemoteRepositoryInterface {
suspend fun registerAccount(data: AccountData): Result<Unit>
suspend fun signIn(data: AccountData): Result<Unit>
suspend fun getAccountStatus(): Result<AccountData>
suspend fun getUploadUrl(key: String, file: File): Result<String>
suspend fun uploadFile(preSignedUrl: String, file: File): Result<Unit>
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ object ExternalCameraModule {

@Singleton
@Provides
fun provideOkHttpClient(
@Named("okHttpExternalCameraClient")
fun provideOkHttpExternalCameraClient(
baseUrlInterceptor: BaseUrlInterceptor
) = OkHttpClient.Builder()
.connectTimeout(AppPolicy.EXTERNAL_CAMERA_CONNECT_TIMEOUT, TimeUnit.SECONDS)
Expand All @@ -42,8 +43,9 @@ object ExternalCameraModule {

@Singleton
@Provides
@Named("externalCameraServerRetrofit")
fun provideExternalCameraServerRetrofit(
okHttpClient: OkHttpClient,
@Named("okHttpExternalCameraClient") okHttpClient: OkHttpClient,
@Named("cameraIPUrl") cameraIPUrl: String
) = Retrofit.Builder()
.baseUrl(cameraIPUrl)
Expand All @@ -56,6 +58,8 @@ object ExternalCameraModule {

@Singleton
@Provides
fun provideApiService(retrofit: Retrofit): ExternalCameraApi =
fun provideExternalCameraApi(
@Named("externalCameraServerRetrofit") retrofit: Retrofit
): ExternalCameraApi =
retrofit.create(ExternalCameraApi::class.java)
}
Loading

0 comments on commit c7d7598

Please sign in to comment.