NTP-50672 | Sohan | FCM Broadcast unsubsciption logic changes. (#15665)
This commit is contained in:
committed by
GitHub
parent
1ebe408f48
commit
3dc917620f
@@ -21,9 +21,9 @@ class ConfigRepository
|
|||||||
constructor(@SuperAppRetroFit private val superAppRetrofitService: RetrofitService) :
|
constructor(@SuperAppRetroFit private val superAppRetrofitService: RetrofitService) :
|
||||||
ResponseCallback() {
|
ResponseCallback() {
|
||||||
|
|
||||||
suspend fun fetchMqttConfig(target: String, naeScreenName: String) =
|
suspend fun fetchKruzConfig(target: String, naeScreenName: String) =
|
||||||
apiResponseCallback(
|
apiResponseCallback(
|
||||||
superAppRetrofitService.fetchMqttConfig(target),
|
superAppRetrofitService.fetchKruzConfig(target),
|
||||||
metricInfo = MetricInfo.AppMetric(screen = naeScreenName, isNae = { false }),
|
metricInfo = MetricInfo.AppMetric(screen = naeScreenName, isNae = { false }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ import com.naviapp.payment.states.BottomSheetInfoV2State
|
|||||||
import com.naviapp.payment.viewmodel.PaymentVM
|
import com.naviapp.payment.viewmodel.PaymentVM
|
||||||
import com.naviapp.registration.helper.isLocationPermissionGranted
|
import com.naviapp.registration.helper.isLocationPermissionGranted
|
||||||
import com.naviapp.registration.helper.isReadSmsPermissionGranted
|
import com.naviapp.registration.helper.isReadSmsPermissionGranted
|
||||||
import com.naviapp.registration.usecase.FcmTopicUseCase
|
|
||||||
import com.naviapp.registration.viewmodel.RegistrationVM
|
import com.naviapp.registration.viewmodel.RegistrationVM
|
||||||
import com.naviapp.registration.viewmodel.UploadUserDataUseCase
|
import com.naviapp.registration.viewmodel.UploadUserDataUseCase
|
||||||
import com.naviapp.screenOverlay.handler.ScreenOverlayEffectHandler
|
import com.naviapp.screenOverlay.handler.ScreenOverlayEffectHandler
|
||||||
@@ -209,8 +208,6 @@ class HomePageActivity :
|
|||||||
|
|
||||||
@Inject lateinit var userDataUseCase: UploadUserDataUseCase
|
@Inject lateinit var userDataUseCase: UploadUserDataUseCase
|
||||||
|
|
||||||
@Inject lateinit var fcmTopicUseCase: FcmTopicUseCase
|
|
||||||
|
|
||||||
@Inject lateinit var screenNavigator: ScreenNavigator
|
@Inject lateinit var screenNavigator: ScreenNavigator
|
||||||
|
|
||||||
@Inject lateinit var permissionsManager: PermissionsManager
|
@Inject lateinit var permissionsManager: PermissionsManager
|
||||||
@@ -294,7 +291,6 @@ class HomePageActivity :
|
|||||||
AppLoadTimerMapper.initActivityStartTime()
|
AppLoadTimerMapper.initActivityStartTime()
|
||||||
installSplashScreen()
|
installSplashScreen()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
fcmTopicUseCase.attachFcmTopics()
|
|
||||||
redirectionUseCase.redirectToDestination(homeVM)
|
redirectionUseCase.redirectToDestination(homeVM)
|
||||||
enableEdgeToEdge(
|
enableEdgeToEdge(
|
||||||
statusBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT)
|
statusBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import com.naviapp.models.request.SaphyraDeviceDetails
|
|||||||
import com.naviapp.models.request.SaphyraRequestData
|
import com.naviapp.models.request.SaphyraRequestData
|
||||||
import com.naviapp.models.response.FirebaseRefreshAuthTokenResponse
|
import com.naviapp.models.response.FirebaseRefreshAuthTokenResponse
|
||||||
import com.naviapp.registration.repositories.RegisterRepository
|
import com.naviapp.registration.repositories.RegisterRepository
|
||||||
import com.naviapp.registration.usecase.MqttSdkInitUseCase
|
import com.naviapp.registration.usecase.RealTimeMessagingInitUseCase
|
||||||
import com.naviapp.utils.Constants.IS_PERMISSION_REQUIRED_ON_HOME
|
import com.naviapp.utils.Constants.IS_PERMISSION_REQUIRED_ON_HOME
|
||||||
import com.naviapp.utils.Constants.OS_ANDROID
|
import com.naviapp.utils.Constants.OS_ANDROID
|
||||||
import com.naviapp.utils.EMPTY
|
import com.naviapp.utils.EMPTY
|
||||||
@@ -62,7 +62,7 @@ open class LauncherVM
|
|||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val configRepository: ConfigRepository,
|
private val configRepository: ConfigRepository,
|
||||||
private val mqttSdkInitUseCase: MqttSdkInitUseCase,
|
private val realTimeMessagingInitUseCase: RealTimeMessagingInitUseCase,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val registerRepository = RegisterRepository()
|
private val registerRepository = RegisterRepository()
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initMqttSDK(naeScreenName: String) {
|
private fun initMqttSDK(naeScreenName: String) {
|
||||||
mqttSdkInitUseCase.initMqttSdk(naeScreenName = naeScreenName)
|
realTimeMessagingInitUseCase.initSdks(naeScreenName = naeScreenName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setFirebaseAppInstanceId() {
|
fun setFirebaseAppInstanceId() {
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ interface RetrofitService {
|
|||||||
): Response<BranchSDKResponse>
|
): Response<BranchSDKResponse>
|
||||||
|
|
||||||
@GET("/kruz/proxy/config")
|
@GET("/kruz/proxy/config")
|
||||||
suspend fun fetchMqttConfig(
|
suspend fun fetchKruzConfig(
|
||||||
@Header("X-Target") channel: String
|
@Header("X-Target") channel: String
|
||||||
): Response<GenericResponse<MqttSdkInitParams>>
|
): Response<GenericResponse<MqttSdkInitParams>>
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.google.firebase.messaging.FirebaseMessaging
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.navi.analytics.utils.NaviTrackEvent
|
import com.navi.analytics.utils.NaviTrackEvent
|
||||||
import com.navi.base.cache.di.NaviCommonGson
|
import com.navi.base.cache.di.NaviCommonGson
|
||||||
|
import com.navi.base.sharedpref.PreferenceManager
|
||||||
import com.navi.base.utils.isNotNullAndNotEmpty
|
import com.navi.base.utils.isNotNullAndNotEmpty
|
||||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.FCM_TOPIC_LIST
|
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.FCM_TOPIC_LIST
|
||||||
@@ -22,12 +23,18 @@ import com.naviapp.utils.Constants.UNKNOWN_ERROR
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use case for managing Firebase Cloud Messaging (FCM) topic subscriptions.
|
* Use case responsible for managing Firebase Cloud Messaging (FCM) topic subscriptions.
|
||||||
*
|
*
|
||||||
* **Note:** This is currently used only for performance testing. We will improve this for all
|
* This class handles:
|
||||||
* modules.
|
* - Subscribing and unsubscribing to FCM topics based on provided strings or Remote Config.
|
||||||
|
* - Tracking success/failure/cancellation events for analytics.
|
||||||
|
* - Storing subscribed topics in shared preferences to manage diffs on next run.
|
||||||
*
|
*
|
||||||
* @property firebaseMessaging The FirebaseMessaging instance used for topic subscription.
|
* Currently used for performance testing, but structured for future expansion.
|
||||||
|
*
|
||||||
|
* @property firebaseRemoteConfigHelper Helper for fetching Remote Config values.
|
||||||
|
* @property firebaseMessaging FirebaseMessaging instance for topic operations.
|
||||||
|
* @property gson Gson instance for parsing remote config topic list JSON.
|
||||||
*/
|
*/
|
||||||
class FcmTopicUseCase
|
class FcmTopicUseCase
|
||||||
@Inject
|
@Inject
|
||||||
@@ -37,22 +44,68 @@ constructor(
|
|||||||
@NaviCommonGson private val gson: Gson,
|
@NaviCommonGson private val gson: Gson,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/** Attaches FCM topics by fetching the topic list and subscribing to the enabled topics. */
|
/**
|
||||||
fun attachFcmTopics() {
|
* Entry point for attaching FCM topics.
|
||||||
val topicList = fetchFcmTopicList() ?: return
|
*
|
||||||
topicList.list
|
* If a list of strings is provided, it will override previous topics. Otherwise, it falls back
|
||||||
?.filter { it.topicName.isNotNullAndNotEmpty() }
|
* to remote config-controlled topic subscriptions.
|
||||||
?.partition { it.enable }
|
*
|
||||||
?.let { (enabled, disabled) ->
|
* @param topics Optional comma-separated list of topic names.
|
||||||
disabled.forEach { unsubscribeToTopic(it.topicName.orEmpty()) }
|
*/
|
||||||
enabled.forEach { subscribeToTopic(it.topicName.orEmpty()) }
|
suspend fun attachFcmTopics(topics: List<String>? = null) {
|
||||||
}
|
if (topics != null) {
|
||||||
|
processManualTopics(topics)
|
||||||
|
} else {
|
||||||
|
processRemoteConfigTopics()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the list of FCM topics from Firebase Remote Config.
|
* Parses the provided comma-separated string and performs:
|
||||||
|
* - Subscriptions to new topics
|
||||||
|
* - Unsubscriptions from old topics not in the new list
|
||||||
|
* - Preference storage to persist current state
|
||||||
*
|
*
|
||||||
* @return The FcmTopicList object if parsing is successful, otherwise null.
|
* @param topics list of topic names.
|
||||||
|
*/
|
||||||
|
private fun processManualTopics(topics: List<String>) {
|
||||||
|
val newTopics = topics.map { it.trim() }.filter { it.isNotEmpty() }.toSet()
|
||||||
|
|
||||||
|
val oldTopics = PreferenceManager.getHashSet(KEY_FCM_SUBSCRIBED_TOPICS) ?: emptySet()
|
||||||
|
val toUnsubscribe = oldTopics - newTopics
|
||||||
|
|
||||||
|
newTopics.forEach { subscribeToTopic(it) }
|
||||||
|
toUnsubscribe.forEach { unsubscribeFromTopic(it) }
|
||||||
|
|
||||||
|
PreferenceManager.setHashSet(KEY_FCM_SUBSCRIBED_TOPICS, HashSet(newTopics))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches topic subscription config from Firebase Remote Config and:
|
||||||
|
* - Subscribes to enabled topics
|
||||||
|
* - Unsubscribes from disabled ones
|
||||||
|
* - Ignores empty or invalid topic names
|
||||||
|
*/
|
||||||
|
private fun processRemoteConfigTopics() {
|
||||||
|
val topicList = fetchFcmTopicList()
|
||||||
|
if (topicList?.list.isNullOrEmpty()) {
|
||||||
|
NaviTrackEvent.trackEvent(FCM_SUBSCRIPTION_LIST_EMPTY)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
topicList?.list?.let { list ->
|
||||||
|
val (enabledTopics, disabledTopics) =
|
||||||
|
list.filter { it.topicName.isNotNullAndNotEmpty() }.partition { it.enable }
|
||||||
|
|
||||||
|
disabledTopics.forEach { unsubscribeFromTopic(it.topicName.orEmpty()) }
|
||||||
|
enabledTopics.forEach { subscribeToTopic(it.topicName.orEmpty()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and parses the FCM topic list JSON from Firebase Remote Config.
|
||||||
|
*
|
||||||
|
* @return Parsed [FcmTopicList] if successful, else null.
|
||||||
*/
|
*/
|
||||||
private fun fetchFcmTopicList(): FcmTopicList? {
|
private fun fetchFcmTopicList(): FcmTopicList? {
|
||||||
return try {
|
return try {
|
||||||
@@ -67,7 +120,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to a specific FCM topic and tracks events based on the result.
|
* Subscribes to a specific FCM topic and tracks analytics events based on outcome.
|
||||||
*
|
*
|
||||||
* @param topicName The name of the topic to subscribe to.
|
* @param topicName The name of the topic to subscribe to.
|
||||||
*/
|
*/
|
||||||
@@ -84,18 +137,18 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.addOnFailureListener { exception ->
|
.addOnFailureListener {
|
||||||
trackFcmEvent(FCM_SUBSCRIPTION_FAILED, topicName, exception.toString())
|
trackFcmEvent(FCM_SUBSCRIPTION_FAILED, topicName, it.toString())
|
||||||
}
|
}
|
||||||
.addOnCanceledListener { trackFcmEvent(FCM_SUBSCRIPTION_CANCELED, topicName) }
|
.addOnCanceledListener { trackFcmEvent(FCM_SUBSCRIPTION_CANCELED, topicName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribes from a specific FCM topic and tracks events based on the result.
|
* Unsubscribes from a specific FCM topic and tracks analytics events based on outcome.
|
||||||
*
|
*
|
||||||
* @param topicName The name of the topic to unsubscribe from.
|
* @param topicName The name of the topic to unsubscribe from.
|
||||||
*/
|
*/
|
||||||
private fun unsubscribeToTopic(topicName: String) {
|
private fun unsubscribeFromTopic(topicName: String) {
|
||||||
firebaseMessaging
|
firebaseMessaging
|
||||||
.unsubscribeFromTopic(topicName)
|
.unsubscribeFromTopic(topicName)
|
||||||
.addOnSuccessListener { trackFcmEvent(FCM_UNSUBSCRIBE_SUCCESS, topicName) }
|
.addOnSuccessListener { trackFcmEvent(FCM_UNSUBSCRIBE_SUCCESS, topicName) }
|
||||||
@@ -108,8 +161,16 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.addOnCanceledListener { trackFcmEvent(FCM_UNSUBSCRIBE_CANCELED, topicName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks a Firebase-related event for subscriptions or unsubscriptions.
|
||||||
|
*
|
||||||
|
* @param eventName The name of the event to track.
|
||||||
|
* @param topicName The topic this event is related to.
|
||||||
|
* @param errorMessage Optional error message if the event failed.
|
||||||
|
*/
|
||||||
private fun trackFcmEvent(eventName: String, topicName: String, errorMessage: String? = null) {
|
private fun trackFcmEvent(eventName: String, topicName: String, errorMessage: String? = null) {
|
||||||
val eventData = mutableMapOf(TOPIC to topicName)
|
val eventData = mutableMapOf(TOPIC to topicName)
|
||||||
errorMessage?.let { eventData[ERROR] = it }
|
errorMessage?.let { eventData[ERROR] = it }
|
||||||
@@ -117,10 +178,13 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FCM_SUBSCRIPTION_SUCCESS = "dev_fcm_subscription_success"
|
|
||||||
private const val FCM_UNSUBSCRIBE_SUCCESS = "dev_fcm_unsubscribe_success"
|
private const val FCM_UNSUBSCRIBE_SUCCESS = "dev_fcm_unsubscribe_success"
|
||||||
private const val FCM_UNSUBSCRIBE_FAILED = "dev_fcm_unsubscribe_failed"
|
private const val FCM_UNSUBSCRIBE_FAILED = "dev_fcm_unsubscribe_failed"
|
||||||
|
private const val FCM_UNSUBSCRIBE_CANCELED = "dev_fcm_unsubscribe_canceled"
|
||||||
|
private const val FCM_SUBSCRIPTION_SUCCESS = "dev_fcm_subscription_success"
|
||||||
private const val FCM_SUBSCRIPTION_FAILED = "dev_fcm_subscription_failed"
|
private const val FCM_SUBSCRIPTION_FAILED = "dev_fcm_subscription_failed"
|
||||||
private const val FCM_SUBSCRIPTION_CANCELED = "dev_fcm_subscription_canceled"
|
private const val FCM_SUBSCRIPTION_CANCELED = "dev_fcm_subscription_canceled"
|
||||||
|
private const val FCM_SUBSCRIPTION_LIST_EMPTY = "dev_fcm_subscription_list_empty"
|
||||||
|
private const val KEY_FCM_SUBSCRIBED_TOPICS = "fcm_subscribed_topics"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * Copyright © 2024-2025 by Navi Technologies Limited
|
|
||||||
* * All rights reserved. Strictly confidential
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.naviapp.registration.usecase
|
|
||||||
|
|
||||||
import com.navi.analytics.utils.NaviTrackEvent
|
|
||||||
import com.navi.base.utils.BaseUtils
|
|
||||||
import com.navi.common.model.ModuleName
|
|
||||||
import com.navi.common.utils.deviceId
|
|
||||||
import com.navi.common.utils.isValidResponse
|
|
||||||
import com.navi.mqtt.MqttManager
|
|
||||||
import com.navi.mqtt.model.MqttSdkInitParams
|
|
||||||
import com.naviapp.BuildConfig
|
|
||||||
import com.naviapp.app.NaviApplication
|
|
||||||
import com.naviapp.common.repository.ConfigRepository
|
|
||||||
import com.naviapp.utils.COMMA
|
|
||||||
import com.naviapp.utils.Constants
|
|
||||||
import com.naviapp.utils.Constants.PAGE_HOME
|
|
||||||
import com.naviapp.utils.MqttMessageProviderImpl
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class MqttSdkInitUseCase
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val configRepository: ConfigRepository,
|
|
||||||
private val mqttMessageProviderImpl: MqttMessageProviderImpl,
|
|
||||||
) {
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
||||||
|
|
||||||
fun initMqttSdk(naeScreenName: String) {
|
|
||||||
scope.launch {
|
|
||||||
if (BaseUtils.isUserLoggedIn()) {
|
|
||||||
val response =
|
|
||||||
configRepository.fetchMqttConfig(
|
|
||||||
ModuleName.KRUZ_PROXY.name,
|
|
||||||
naeScreenName = naeScreenName,
|
|
||||||
)
|
|
||||||
response
|
|
||||||
.takeIf { it.isValidResponse() }
|
|
||||||
?.data
|
|
||||||
?.let { data ->
|
|
||||||
if (data.enable == true) {
|
|
||||||
val clientIdWithTopics =
|
|
||||||
if (data.topics.isNullOrEmpty()) Constants.EMPTY
|
|
||||||
else addClientIdToTopics(data.topics.orEmpty(), deviceId)
|
|
||||||
MqttManager.init(
|
|
||||||
NaviApplication.instance,
|
|
||||||
MqttSdkInitParams(
|
|
||||||
username = BuildConfig.MQTT_USERNAME,
|
|
||||||
password = BuildConfig.MQTT_PASSWORD,
|
|
||||||
clientId = deviceId,
|
|
||||||
brokerIP = data.brokerIP.orEmpty(),
|
|
||||||
port =
|
|
||||||
data.port
|
|
||||||
?: com.navi.common.utils.Constants.MQTT_DEFAULT_PORT,
|
|
||||||
scheme = data.scheme.orEmpty(),
|
|
||||||
keepAlive =
|
|
||||||
data.keepAlive
|
|
||||||
?: com.navi.common.utils.Constants.MQTT_KEEP_ALIVE,
|
|
||||||
topics = clientIdWithTopics,
|
|
||||||
subscribeQos = data.subscribeQos,
|
|
||||||
cleanSession = data.cleanSession,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
MqttManager.subscribe(
|
|
||||||
clientIdWithTopics,
|
|
||||||
PAGE_HOME,
|
|
||||||
mqttMessageProviderImpl,
|
|
||||||
data.subscribeQos,
|
|
||||||
)
|
|
||||||
NaviTrackEvent.trackEvent("mqtt_sdk_init_triggered")
|
|
||||||
} else {
|
|
||||||
NaviTrackEvent.trackEvent("mqtt_config_enabled_false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?: NaviTrackEvent.trackEvent(
|
|
||||||
"mqtt_config_fetch_failed",
|
|
||||||
mapOf("error" to response.error?.message.orEmpty()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addClientIdToTopics(data: String, clientId: String): String {
|
|
||||||
val topics = data.split(COMMA)
|
|
||||||
val modifiedTopics = topics.map { "$it/$clientId" }
|
|
||||||
return modifiedTopics.joinToString(COMMA)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Copyright © 2025 by Navi Technologies Limited
|
||||||
|
* * All rights reserved. Strictly confidential
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.naviapp.registration.usecase
|
||||||
|
|
||||||
|
import com.navi.analytics.utils.NaviTrackEvent
|
||||||
|
import com.navi.base.utils.coroutine.CoroutineManager
|
||||||
|
import com.navi.common.model.ModuleName
|
||||||
|
import com.navi.common.utils.deviceId
|
||||||
|
import com.navi.common.utils.isValidResponse
|
||||||
|
import com.navi.mqtt.MqttManager
|
||||||
|
import com.navi.mqtt.model.MqttSdkInitParams
|
||||||
|
import com.naviapp.BuildConfig
|
||||||
|
import com.naviapp.app.NaviApplication
|
||||||
|
import com.naviapp.common.repository.ConfigRepository
|
||||||
|
import com.naviapp.utils.COMMA
|
||||||
|
import com.naviapp.utils.Constants
|
||||||
|
import com.naviapp.utils.Constants.PAGE_HOME
|
||||||
|
import com.naviapp.utils.Constants.SLASH
|
||||||
|
import com.naviapp.utils.MqttMessageProviderImpl
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RealTimeMessagingInitUseCase
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val configRepository: ConfigRepository,
|
||||||
|
private val mqttMessageProviderImpl: MqttMessageProviderImpl,
|
||||||
|
private val fcmTopicUseCase: FcmTopicUseCase,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initSdks(naeScreenName: String) {
|
||||||
|
CoroutineManager.scope.launchOnIO {
|
||||||
|
val response =
|
||||||
|
configRepository.fetchKruzConfig(
|
||||||
|
ModuleName.KRUZ_PROXY.name,
|
||||||
|
naeScreenName = naeScreenName,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!response.isValidResponse()) {
|
||||||
|
trackError(response.error?.message.orEmpty())
|
||||||
|
return@launchOnIO
|
||||||
|
}
|
||||||
|
|
||||||
|
val data =
|
||||||
|
response.data
|
||||||
|
?: run {
|
||||||
|
trackError(MSG_RESPONSE_DATA_NULL)
|
||||||
|
return@launchOnIO
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMqttIfEnabled(data)
|
||||||
|
setupFcmTopics(data.fcmTopics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupMqttIfEnabled(data: MqttSdkInitParams) {
|
||||||
|
if (data.enable != true) {
|
||||||
|
NaviTrackEvent.trackEvent(EVENT_MQTT_CONFIG_DISABLED)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val clientIdWithTopics =
|
||||||
|
data.topics?.takeIf { it.isNotEmpty() }?.let { addClientIdToTopics(it, deviceId) }
|
||||||
|
?: Constants.EMPTY
|
||||||
|
|
||||||
|
MqttManager.init(
|
||||||
|
NaviApplication.instance,
|
||||||
|
MqttSdkInitParams(
|
||||||
|
username = BuildConfig.MQTT_USERNAME,
|
||||||
|
password = BuildConfig.MQTT_PASSWORD,
|
||||||
|
clientId = deviceId,
|
||||||
|
brokerIP = data.brokerIP.orEmpty(),
|
||||||
|
port = data.port ?: com.navi.common.utils.Constants.MQTT_DEFAULT_PORT,
|
||||||
|
scheme = data.scheme.orEmpty(),
|
||||||
|
keepAlive = data.keepAlive ?: com.navi.common.utils.Constants.MQTT_KEEP_ALIVE,
|
||||||
|
topics = clientIdWithTopics,
|
||||||
|
subscribeQos = data.subscribeQos,
|
||||||
|
cleanSession = data.cleanSession,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
MqttManager.subscribe(
|
||||||
|
clientIdWithTopics,
|
||||||
|
PAGE_HOME,
|
||||||
|
mqttMessageProviderImpl,
|
||||||
|
data.subscribeQos,
|
||||||
|
)
|
||||||
|
|
||||||
|
NaviTrackEvent.trackEvent(EVENT_MQTT_SDK_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun setupFcmTopics(fcmTopics: List<String>?) {
|
||||||
|
fcmTopicUseCase.attachFcmTopics(fcmTopics)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun trackError(error: String) {
|
||||||
|
NaviTrackEvent.trackEvent(EVENT_CONFIG_FETCH_FAILED, mapOf(KEY_ERROR to error))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addClientIdToTopics(data: String, clientId: String): String {
|
||||||
|
return data.split(COMMA).joinToString(COMMA) {
|
||||||
|
buildString {
|
||||||
|
append(it)
|
||||||
|
append(SLASH)
|
||||||
|
append(clientId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val EVENT_MQTT_SDK_INIT = "mqtt_sdk_init_triggered"
|
||||||
|
private const val EVENT_MQTT_CONFIG_DISABLED = "mqtt_config_enabled_false"
|
||||||
|
private const val EVENT_CONFIG_FETCH_FAILED = "dev_kruz_config_fetch_failed"
|
||||||
|
private const val KEY_ERROR = "error"
|
||||||
|
private const val MSG_RESPONSE_DATA_NULL = "Response data is null"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import io.mockk.mockk
|
|||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
@@ -38,7 +39,7 @@ class FcmTopicUseCaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `attachFcmTopics calls subscribeToTopic when enabled list is not empty`() {
|
fun `attachFcmTopics calls subscribeToTopic when enabled list is not empty`() = runTest {
|
||||||
val topicName = "test_topic"
|
val topicName = "test_topic"
|
||||||
val fcmTopicList = FcmTopicList(listOf(FcmTopicData(topicName, enable = true)))
|
val fcmTopicList = FcmTopicList(listOf(FcmTopicData(topicName, enable = true)))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* * Copyright © 2024 by Navi Technologies Limited
|
* * Copyright © 2024-2025 by Navi Technologies Limited
|
||||||
* * All rights reserved. Strictly confidential
|
* * All rights reserved. Strictly confidential
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -14,6 +14,7 @@ data class MqttSdkInitParams(
|
|||||||
val username: String? = null,
|
val username: String? = null,
|
||||||
val password: String? = null,
|
val password: String? = null,
|
||||||
val clientId: String? = null,
|
val clientId: String? = null,
|
||||||
|
val fcmTopics: List<String>? = null,
|
||||||
@SerializedName("port") val port: Int? = null,
|
@SerializedName("port") val port: Int? = null,
|
||||||
@SerializedName("scheme") val scheme: String? = null,
|
@SerializedName("scheme") val scheme: String? = null,
|
||||||
@SerializedName("keepAlive") val keepAlive: Int? = 30,
|
@SerializedName("keepAlive") val keepAlive: Int? = 30,
|
||||||
|
|||||||
Reference in New Issue
Block a user