Skip to content

Commit

Permalink
Merge pull request #322 from 6QuizOnTheBlock/and/feat#301-sse
Browse files Browse the repository at this point in the history
And/feat#301 sse
  • Loading branch information
TRASALBY authored May 13, 2024
2 parents 887f101 + 93a93ed commit f28518f
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.sixkids.model

enum class SseEventType {
SSE_CONNECT,
INVITE_REQUEST,
INVITE_RESPONSE,
KICK_MEMBER,
CREATE_GROUP,
}
20 changes: 10 additions & 10 deletions android/data/src/main/java/com/sixkids/data/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package com.sixkids.data.di

import com.sixkids.data.repository.organization.remote.OrganizationRemoteDataSource
import com.sixkids.data.repository.organization.remote.OrganizationRemoteDataSourceImpl
import com.sixkids.data.repository.user.local.UserLocalDataSource
import com.sixkids.data.repository.user.local.UserLocalDataSourceImpl
import com.sixkids.data.repository.user.remote.UserRemoteDataSource
import com.sixkids.data.repository.user.remote.UserRemoteDataSourceImpl
import com.sixkids.data.repository.challenge.remote.ChallengeRemoteDataSource
import com.sixkids.data.repository.challenge.remote.ChallengeRemoteDataSourceImpl
import com.sixkids.data.repository.comment.remote.CommentRemoteDataSource
import com.sixkids.data.repository.comment.remote.CommentRemoteDataSourceImpl
import com.sixkids.data.repository.chatting.remote.ChattingRemoteDataSource
import com.sixkids.data.repository.chatting.remote.ChattingRemoteDataSourceImpl
import com.sixkids.data.repository.comment.remote.CommentRemoteDataSource
import com.sixkids.data.repository.comment.remote.CommentRemoteDataSourceImpl
import com.sixkids.data.repository.organization.local.OrganizationLocalDataSource
import com.sixkids.data.repository.organization.local.OrganizationLocalDataSourceImpl
import com.sixkids.data.repository.organization.remote.OrganizationRemoteDataSource
import com.sixkids.data.repository.organization.remote.OrganizationRemoteDataSourceImpl
import com.sixkids.data.repository.post.remote.PostRemoteDataSource
import com.sixkids.data.repository.post.remote.PostRemoteDataSourceImpl
import com.sixkids.data.repository.relay.remote.RelayRemoteDataSource
import com.sixkids.data.repository.relay.remote.RelayRemoteDataSourceImpl
import com.sixkids.data.repository.user.local.UserLocalDataSource
import com.sixkids.data.repository.user.local.UserLocalDataSourceImpl
import com.sixkids.data.repository.user.remote.UserRemoteDataSource
import com.sixkids.data.repository.user.remote.UserRemoteDataSourceImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -40,7 +40,7 @@ abstract class DataSourceModule {
abstract fun bindChallengeDataSource(
challengeRemoteDataSource: ChallengeRemoteDataSourceImpl
): ChallengeRemoteDataSource

@Binds
abstract fun bindOrganizationRemoteDataSource(
organizationRemoteDataSource: OrganizationRemoteDataSourceImpl
Expand All @@ -60,7 +60,7 @@ abstract class DataSourceModule {
abstract fun bindCommentRemoteDataSource(
commentRemoteDataSource: CommentRemoteDataSourceImpl
): CommentRemoteDataSource

@Binds
abstract fun bindChattingRemoteDataSource(
chattingRemoteDataSource: ChattingRemoteDataSourceImpl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package com.sixkids.data.di

import com.sixkids.data.repository.TokenRepositoryImpl
import com.sixkids.data.repository.challenge.ChallengeRepositoryImpl
import com.sixkids.data.repository.comment.CommentRepositoryImpl
import com.sixkids.data.repository.chatting.ChattingRepositoryImpl
import com.sixkids.data.repository.comment.CommentRepositoryImpl
import com.sixkids.data.repository.organization.OrganizationRepositoryImpl
import com.sixkids.data.repository.post.PostRepositoryImpl
import com.sixkids.data.repository.relay.RelayRepositoryImpl
import com.sixkids.domain.repository.ChallengeRepository
import com.sixkids.data.repository.user.UserRepositoryImpl
import com.sixkids.domain.repository.CommentRepository
import com.sixkids.domain.repository.ChallengeRepository
import com.sixkids.domain.repository.ChattingRepository
import com.sixkids.domain.repository.CommentRepository
import com.sixkids.domain.repository.OrganizationRepository
import com.sixkids.domain.repository.PostRepository
import com.sixkids.domain.repository.RelayRepository
Expand Down Expand Up @@ -61,7 +61,7 @@ abstract class RepositoryModule {
abstract fun bindCommentRepository(
commentRepository: CommentRepositoryImpl
): CommentRepository

@Singleton
@Binds
abstract fun bindChattingRepository(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ interface ChallengeRemoteDataSource {
suspend fun getChallengeSimple(
challengeId: Int
): Challenge

suspend fun connectSse()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import com.sixkids.data.model.request.ChallengeCreateRequest
import com.sixkids.data.model.request.GroupRequest
import com.sixkids.data.model.response.toModel
import com.sixkids.model.AcceptStatus
import com.sixkids.model.ChallengeDetail
import com.sixkids.model.Challenge
import com.sixkids.model.ChallengeDetail
import com.sixkids.model.GroupSimple
import java.time.LocalDateTime
import javax.inject.Inject
Expand Down Expand Up @@ -45,8 +45,12 @@ class ChallengeRemoteDataSourceImpl @Inject constructor(
)
).getOrThrow().data

override suspend fun getChallengeSimple(challengeId: Int): Challenge
= challengeService.getChallengeSimple(challengeId).getOrThrow().data.toModel()
override suspend fun getChallengeSimple(challengeId: Int): Challenge =
challengeService.getChallengeSimple(challengeId).getOrThrow().data.toModel()

override suspend fun connectSse() {

}

override suspend fun getChallengeDetail(challengeId: Long, groupId: Long?): ChallengeDetail =
challengeService.getChallengeDetail(challengeId, groupId).getOrThrow().data.toModel()
Expand Down
23 changes: 23 additions & 0 deletions android/feature/student/challenge/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import java.util.Properties

plugins {
alias(libs.plugins.sixkids.android.feature.compose)
}

fun getProperty(propertyKey: String): String =
gradleLocalProperties(rootDir, providers).getProperty(propertyKey)

android {
namespace = "com.sixkids.student.challenge"
defaultConfig {
val localProperties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localProperties.load(localPropertiesFile.inputStream())
}

val sseUrl = localProperties.getProperty("SSE_ENDPOINT") ?: ""

buildConfigField("String", "SSE_ENDPOINT", "\"${sseUrl}\"")
}

buildFeatures {
buildConfig = true
}
}

dependencies {
implementation(libs.bundles.paging)
implementation(projects.core.bluetooth)
implementation(libs.okhttp.sse)
implementation(libs.okhttp.logginginterceptor)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ fun JoinGroupRoute(
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

LaunchedEffect(Unit) {
viewModel.connectSse()
viewModel.loadUserInfo()
viewModel.startAdvertise()
}

DisposableEffect(Unit) {
onDispose {
viewModel.disconnectSse()
viewModel.stopAdvertise()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,115 @@
package com.sixkids.student.group.join

import android.util.Log
import androidx.lifecycle.viewModelScope
import com.sixkids.core.bluetooth.BluetoothServer
import com.sixkids.domain.usecase.user.GetATKUseCase
import com.sixkids.domain.usecase.user.LoadUserInfoUseCase
import com.sixkids.model.MemberSimple
import com.sixkids.student.challenge.BuildConfig
import com.sixkids.ui.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.sse.EventSource
import okhttp3.sse.EventSourceListener
import okhttp3.sse.EventSources
import okio.IOException
import java.util.concurrent.TimeUnit
import javax.inject.Inject

private const val TAG = "D107"

@HiltViewModel
class JoinGroupViewModel @Inject constructor(
private val bluetoothServer: BluetoothServer,
private val loadUserInfoUseCase: LoadUserInfoUseCase
private val loadUserInfoUseCase: LoadUserInfoUseCase,
private val getATKUseCase: GetATKUseCase
) : BaseViewModel<JoinGroupState, JoinGroupEffect>(JoinGroupState()) {

private var eventSource: EventSource? = null

private val client = OkHttpClient.Builder()
.addInterceptor {
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.HEADERS
}.intercept(it)
}
.connectTimeout(10, TimeUnit.MINUTES)
.readTimeout(10, TimeUnit.MINUTES)
.writeTimeout(10, TimeUnit.MINUTES)
.build()

private val request = Request.Builder()
.url(BuildConfig.SSE_ENDPOINT)
.header("Authorization", "Bearer ${runBlocking { getATKUseCase().getOrNull() }}")
.build()

private val eventSourceListener = object : EventSourceListener() {
override fun onOpen(eventSource: EventSource, response: Response) {
super.onOpen(eventSource, response)
Log.d(TAG, "Connection Opened")
}

override fun onClosed(eventSource: EventSource) {
super.onClosed(eventSource)
Log.d(TAG, "Connection Closed")
}

override fun onEvent(
eventSource: EventSource,
id: String?,
type: String?,
data: String
) {
super.onEvent(eventSource, id, type, data)
Log.d(TAG, "On Event Received! Data -: $data")
}

override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
super.onFailure(eventSource, t, response)
Log.d(TAG, "On Failure -: ${response?.body}")
}
}

init {
// sseConnectUseCase.setEventListener(this)


}

fun connectSse() = viewModelScope.launch {
eventSource = EventSources.createFactory(client)
.newEventSource(request, eventSourceListener)

viewModelScope.launch {
withContext(Dispatchers.IO) {
client.newCall(request).enqueue(responseCallback = object : Callback {
override fun onFailure(call: Call, e: IOException) {
throw e
}

override fun onResponse(call: Call, response: Response) {
Log.d(TAG, "APi Call Success ${response.body}")
}
})
}
}
}

fun disconnectSse() {
eventSource?.cancel()
eventSource = null
}

fun loadUserInfo() {
viewModelScope.launch {
loadUserInfoUseCase().onSuccess {
Expand Down
2 changes: 2 additions & 0 deletions android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ retrofit = "2.9.0"
moshi-converter = "2.9.0"
moshi-kotlin = "1.14.0"
okhttp = "4.9.1"
okhttp-sse = "4.9.3"
logging-interceptor = "4.8.0"

#DataStore
Expand Down Expand Up @@ -108,6 +109,7 @@ moshi-converter = { group = "com.squareup.retrofit2", name = "converter-moshi",
moshi-kotlin = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi-kotlin" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
okhttp-logginginterceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "logging-interceptor" }
okhttp-sse = { group = "com.squareup.okhttp3", name = "okhttp-sse", version.ref = "okhttp-sse" }

datastore = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }

Expand Down

0 comments on commit f28518f

Please sign in to comment.