Skip to content

Commit

Permalink
Merge branch 'develop' into fix/self-user-refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
sbakhtiarov authored Jan 15, 2025
2 parents 9f3cf5c + 2a6796a commit cb2c078
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ class ChangeProfilingUseCase(
private val userStorage: UserStorage,
) {
/**
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
* @param enabled true to enable profiling, false to disable
* Change profiling state.
*/
operator fun invoke(enabled: Boolean) {
userStorage.database.changeProfiling(enabled)
suspend operator fun invoke(enabled: Boolean) {
userStorage.database.debugExtension.changeProfiling(enabled)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class DebugScope internal constructor(
private val legalHoldHandler: LegalHoldHandler,
private val notificationTokenRepository: NotificationTokenRepository,
private val scope: CoroutineScope,
userStorage: UserStorage,
private val userStorage: UserStorage,
logger: KaliumLogger,
internal val dispatcher: KaliumDispatcher = KaliumDispatcherImpl,
) {
Expand Down Expand Up @@ -227,5 +227,7 @@ class DebugScope internal constructor(
notificationTokenRepository,
)

val changeProfiling: ChangeProfilingUseCase = ChangeProfilingUseCase(userStorage)
val changeProfiling: ChangeProfilingUseCase get() = ChangeProfilingUseCase(userStorage)

val observeDatabaseLoggerState get() = ObserveDatabaseLoggerStateUseCase(userStorage)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.logic.feature.debug

import com.wire.kalium.logic.di.UserStorage
import kotlinx.coroutines.flow.Flow

/**
* Use case to observe the state of the database logger.
*/
class ObserveDatabaseLoggerStateUseCase(
private val userStorage: UserStorage,
) {
suspend operator fun invoke(): Flow<Boolean> = userStorage.database.debugExtension.observeIsProfilingEnabled()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence.db

internal actual fun platformDatabaseLogger(): String = "logcat"
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ actual fun userDatabaseBuilder(
dispatcher = dispatcher,
platformDatabaseData = platformDatabaseData,
isEncrypted = isEncryptionEnabled,
cipherProfile = "logcat",
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence.db

internal actual fun platformDatabaseLogger(): String = "os_log"
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence.db

import app.cash.sqldelight.db.QueryResult
import app.cash.sqldelight.db.SqlDriver
import com.wire.kalium.persistence.dao.MetadataDAO
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class DebugExtension(
private val sqlDriver: SqlDriver,
private val isEncrypted: Boolean,
private val metaDataDao: MetadataDAO,
) {

suspend fun observeIsProfilingEnabled(): Flow<Boolean> =
metaDataDao.valueByKeyFlow(KEY_CIPHER_PROFILE)
.map { state ->
state?.let { DBProfile.fromString(it) }.let {
it is DBProfile.ON
}
}

/**
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
* @param enabled true to enable profiling, false to disable
*/
suspend fun changeProfiling(enabled: Boolean): Long? =
if (isEncrypted) {
val state = if (enabled) DBProfile.ON.Device else DBProfile.Off
sqlDriver.executeQuery(
identifier = null,
sql = """PRAGMA cipher_profile= '${state.logTarget}';""",
mapper = { cursor ->
cursor.next()
cursor.getLong(0).let { QueryResult.Value<Long?>(it) }
},
parameters = 0,
).value.also {
updateMetadata(state)
}

} else {
error("Cannot change profiling on unencrypted database")
}

private suspend fun updateMetadata(state: DBProfile) {
metaDataDao.insertValue(
value = state.logTarget,
key = KEY_CIPHER_PROFILE
)
}

private companion object {
const val KEY_CIPHER_PROFILE = "cipher_profile"
}
}

sealed interface DBProfile {
val logTarget: String

data object Off : DBProfile {
override val logTarget: String = "off"

override fun toString(): String {
return "off"
}
}

sealed interface ON : DBProfile {
data object Device : ON {
override val logTarget: String = "logcat"

override fun toString(): String {
return platformDatabaseLogger()
}
}

data class CustomFile(override val logTarget: String) : ON {
override fun toString(): String {
return logTarget
}
}
}

companion object {
fun fromString(value: String): DBProfile = when (value) {
"off" -> Off
platformDatabaseLogger() -> ON.Device
else -> ON.CustomFile(value)
}
}
}

internal expect fun platformDatabaseLogger(): String
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ class UserDatabaseBuilder internal constructor(
private val platformDatabaseData: PlatformDatabaseData,
private val isEncrypted: Boolean,
private val queriesContext: CoroutineContext = KaliumDispatcherImpl.io,
private val cipherProfile: String? = null,
) {

internal val database: UserDatabase = UserDatabase(
Expand Down Expand Up @@ -314,30 +313,18 @@ class UserDatabaseBuilder internal constructor(
queriesContext
)

val debugExtension: DebugExtension
get() = DebugExtension(
sqlDriver = sqlDriver,
metaDataDao = metadataDAO,
isEncrypted = isEncrypted
)

/**
* @return the absolute path of the DB file or null if the DB file does not exist
*/
fun dbFileLocation(): String? = getDatabaseAbsoluteFileLocation(platformDatabaseData, userId)

/**
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
* @param enabled true to enable profiling, false to disable
*/
fun changeProfiling(enabled: Boolean) {
if (isEncrypted && cipherProfile != null) {
val cipherProfileValue = if (enabled) cipherProfile else "off"
sqlDriver.executeQuery(
identifier = null,
sql = "PRAGMA cipher_profile='$cipherProfileValue'",
mapper = {
it.next()
it.getLong(0).let { QueryResult.Value<Long?>(it) }
},
parameters = 0,
)
}
}

/**
* drops DB connection and delete the DB file
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,44 +484,6 @@ class ClientDAOTest : BaseDatabaseTest() {
assertNull(clientDAO.isMLSCapable(userId, clientId = client.id))
}

@Test
fun givenPersistedClient_whenUpsertingTheSameExactClient_thenItShouldIgnoreAndNotNotifyOtherQueries() = runTest {
// Given
userDAO.upsertUser(user)
clientDAO.insertClient(insertedClient)

clientDAO.observeClient(user.id, insertedClient.id).test {
val initialValue = awaitItem()
assertEquals(insertedClient.toClient(), initialValue)

// When
clientDAO.insertClient(insertedClient) // the same exact client is being saved again

// Then
expectNoEvents() // other query should not be notified
}
}

@Test
fun givenPersistedClient_whenUpsertingUpdatedClient_thenItShouldBeSavedAndOtherQueriesShouldBeUpdated() = runTest {
// Given
userDAO.upsertUser(user)
clientDAO.insertClient(insertedClient)
val updatedInsertedClient = insertedClient.copy(label = "new_label")

clientDAO.observeClient(user.id, insertedClient.id).test {
val initialValue = awaitItem()
assertEquals(insertedClient.toClient(), initialValue)

// When
clientDAO.insertClient(updatedInsertedClient) // updated client is being saved that should replace the old one

// Then
val updatedValue = awaitItem() // other query should be notified
assertEquals(updatedInsertedClient.toClient(), updatedValue)
}
}

private companion object {
val userId = QualifiedIDEntity("test", "domain")
val user = newUserEntity(userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence.db

internal actual fun platformDatabaseLogger(): String {
TODO("Not yet implemented")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence.db

internal actual fun platformDatabaseLogger(): String {
TODO("Not yet implemented")
}

0 comments on commit cb2c078

Please sign in to comment.