-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #459 from mysteriumnetwork/feature/Replace_matomo_…
…analitics Replace matomo analitics
- Loading branch information
Showing
26 changed files
with
554 additions
and
210 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 0 additions & 11 deletions
11
android/app/src/main/java/updated/mysterium/vpn/analitics/AnalyticEvent.kt
This file was deleted.
Oops, something went wrong.
121 changes: 0 additions & 121 deletions
121
android/app/src/main/java/updated/mysterium/vpn/analitics/AnalyticWrapper.kt
This file was deleted.
Oops, something went wrong.
15 changes: 15 additions & 0 deletions
15
android/app/src/main/java/updated/mysterium/vpn/analytics/AnalyticEvent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package updated.mysterium.vpn.analytics | ||
|
||
enum class AnalyticEvent(val eventName: String) { | ||
STARTUP("startup"), | ||
CONNECT_ATTEMPT("connect_attempt"), | ||
CONNECT_SUCCESS("connect_success"), | ||
CONNECT_FAILURE("connect_failure"), | ||
MANUAL_CONNECT("manual_connect"), | ||
QUICK_CONNECT("quick_connect"), | ||
DISCONNECT_ATTEMPT("disconnect_attempt"), | ||
DISCONNECT_SUCCESS("disconnect_success"), | ||
DISCONNECT_FAILURE("disconnect_failure"), | ||
PAGE_VIEW("page_view"), | ||
BALANCE_UPDATE("balance_update") | ||
} |
63 changes: 63 additions & 0 deletions
63
android/app/src/main/java/updated/mysterium/vpn/analytics/AnalyticWrapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package updated.mysterium.vpn.analytics | ||
|
||
import android.util.Log | ||
import retrofit2.Call | ||
import retrofit2.Callback | ||
import retrofit2.Response | ||
import updated.mysterium.vpn.analytics.mysterium.MysteriumAnalyticService | ||
import updated.mysterium.vpn.model.analytics.ClientAnalyticRequest | ||
import updated.mysterium.vpn.model.analytics.EventAnalyticRequest | ||
|
||
class AnalyticWrapper { | ||
|
||
private companion object { | ||
const val SUCCESS_TRACK_CODE = 202 | ||
const val TAG = "AnalyticWrapper" | ||
} | ||
|
||
private var apiInterface = MysteriumAnalyticService.analyticService | ||
|
||
fun trackEvent(event: ClientAnalyticRequest, retry: Boolean = false) { | ||
Log.i(TAG, event.toString()) | ||
val call = apiInterface.trackEvent(event) | ||
call?.enqueue( | ||
object : Callback<Unit?> { | ||
|
||
override fun onResponse(call: Call<Unit?>, response: Response<Unit?>) { | ||
if (response.code() != SUCCESS_TRACK_CODE && retry.not()) { | ||
trackEvent(event, true) | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<Unit?>, throwable: Throwable) { | ||
Log.i(TAG, throwable.localizedMessage ?: throwable.toString()) | ||
if (retry.not()) { | ||
trackEvent(event, true) | ||
} | ||
} | ||
} | ||
) | ||
} | ||
|
||
fun trackEvent(event: EventAnalyticRequest, retry: Boolean = false) { | ||
Log.i(TAG, event.toString()) | ||
val call = apiInterface.trackEvent(event) | ||
call?.enqueue( | ||
object : Callback<Unit?> { | ||
|
||
override fun onResponse(call: Call<Unit?>, response: Response<Unit?>) { | ||
if (response.code() != SUCCESS_TRACK_CODE && retry.not()) { | ||
trackEvent(event, true) | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<Unit?>, throwable: Throwable) { | ||
Log.i(TAG, throwable.localizedMessage ?: throwable.toString()) | ||
if (retry.not()) { | ||
trackEvent(event, true) | ||
} | ||
} | ||
} | ||
) | ||
} | ||
} |
143 changes: 143 additions & 0 deletions
143
android/app/src/main/java/updated/mysterium/vpn/analytics/mysterium/MysteriumAnalytic.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package updated.mysterium.vpn.analytics.mysterium | ||
|
||
import android.content.Context | ||
import android.util.Log | ||
import kotlinx.coroutines.CoroutineExceptionHandler | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.SharedFlow | ||
import kotlinx.coroutines.launch | ||
import mysterium.GetBalanceRequest | ||
import updated.mysterium.vpn.analytics.AnalyticEvent | ||
import updated.mysterium.vpn.analytics.AnalyticWrapper | ||
import updated.mysterium.vpn.common.data.DeviceUtil | ||
import updated.mysterium.vpn.model.analytics.ClientAnalyticRequest | ||
import updated.mysterium.vpn.model.analytics.ClientInfo | ||
import updated.mysterium.vpn.model.analytics.EventAnalyticRequest | ||
import updated.mysterium.vpn.model.manual.connect.Proposal | ||
import updated.mysterium.vpn.model.wallet.IdentityModel | ||
import updated.mysterium.vpn.model.wallet.IdentityRegistrationStatus | ||
import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider | ||
|
||
class MysteriumAnalytic( | ||
context: Context, | ||
private val analyticWrapper: AnalyticWrapper, | ||
useCaseProvider: UseCaseProvider | ||
) { | ||
|
||
private companion object { | ||
const val TAG = "MysteriumAnalytic" | ||
} | ||
|
||
val eventTracked: SharedFlow<String> | ||
get() = _eventTracked | ||
private val _eventTracked = MutableSharedFlow<String>() | ||
|
||
private val connectionUseCase = useCaseProvider.connection() | ||
private val balanceUseCase = useCaseProvider.balance() | ||
private var balanceRequest: GetBalanceRequest? = null | ||
|
||
private val machineID = DeviceUtil.getDeviceID(context.contentResolver) | ||
private val appVersion = DeviceUtil.getAppVersion(context) | ||
private val osVersion = DeviceUtil.getAndroidVersion() | ||
private val country = DeviceUtil.getConfiguredCountry(context) | ||
private val scope = CoroutineScope(Dispatchers.IO) | ||
|
||
fun trackEvent( | ||
eventName: String, | ||
pageTitle: String? = null, | ||
proposal: Proposal? = null | ||
) { | ||
val handler = CoroutineExceptionHandler { _, exception -> | ||
Log.e(TAG, exception.localizedMessage ?: exception.toString()) | ||
_eventTracked.tryEmit(eventName) | ||
} | ||
|
||
scope.launch(handler) { | ||
requestEventTracking(eventName, pageTitle, proposal) | ||
} | ||
} | ||
|
||
private suspend fun requestEventTracking( | ||
eventName: String, | ||
pageTitle: String? = null, | ||
proposal: Proposal? = null | ||
) { | ||
if (eventName == AnalyticEvent.STARTUP.eventName) { | ||
val clientInfo = getClientInfo() | ||
val clientAnalyticRequest = ClientAnalyticRequest( | ||
eventName, | ||
clientInfo | ||
) | ||
analyticWrapper.trackEvent(clientAnalyticRequest) | ||
_eventTracked.emit(eventName) | ||
} else { | ||
val analyticRequest = getAnalyticRequest( | ||
eventName, proposal, pageTitle | ||
) | ||
analyticWrapper.trackEvent(analyticRequest) | ||
_eventTracked.emit(eventName) | ||
} | ||
} | ||
|
||
private fun getClientInfo(): ClientInfo { | ||
val identityAddress = connectionUseCase.getSavedIdentityAddress() | ||
return ClientInfo( | ||
machineID = machineID, | ||
appVersion = appVersion, | ||
osVersion = osVersion, | ||
country = country, | ||
consumerID = identityAddress | ||
) | ||
} | ||
|
||
private suspend fun getAnalyticRequest( | ||
eventName: String, | ||
proposal: Proposal?, | ||
pageTitle: String? | ||
): EventAnalyticRequest { | ||
|
||
// client | ||
val clientInfo = getClientInfo() | ||
|
||
// duration | ||
var duration: Long? = connectionUseCase.getDuration() | ||
if (duration == 0L) { | ||
duration = null | ||
} | ||
|
||
// balance | ||
initBalanceRequest() | ||
var balance: Double? = null | ||
balanceRequest?.let { | ||
balance = balanceUseCase.getBalance(it) | ||
} | ||
|
||
// country, providerID | ||
val country = proposal?.countryName | ||
val providerID = proposal?.providerID | ||
|
||
return EventAnalyticRequest( | ||
eventName = eventName, | ||
duration = duration, | ||
balance = balance, | ||
country = country, | ||
providerID = providerID, | ||
pageTitle = pageTitle, | ||
clientInfo = clientInfo | ||
) | ||
} | ||
|
||
private suspend fun initBalanceRequest() { | ||
val nodeIdentity = connectionUseCase.getIdentity() | ||
val identity = IdentityModel( | ||
address = nodeIdentity.address, | ||
channelAddress = nodeIdentity.channelAddress, | ||
status = IdentityRegistrationStatus.parse(nodeIdentity.registrationStatus) | ||
) | ||
balanceRequest = GetBalanceRequest().apply { | ||
identityAddress = identity.address | ||
} | ||
} | ||
} |
Oops, something went wrong.