diff --git a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt index 8f4d1a803f..fa08d5e91a 100644 --- a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt +++ b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt @@ -1,7 +1,6 @@ package com.flipperdevices.bridge.connection.config.api import com.flipperdevices.bridge.connection.config.api.model.FDeviceBaseModel -import com.flipperdevices.core.preference.pb.SavedDevice import kotlinx.coroutines.flow.Flow interface FDevicePersistedStorage { diff --git a/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt b/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt index 78b1e42839..750ca644d7 100644 --- a/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt +++ b/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt @@ -9,7 +9,6 @@ import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.info import com.flipperdevices.core.log.warn import com.flipperdevices.core.preference.pb.FlipperZeroBle -import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor import com.flipperdevices.core.preference.pb.NewPairSettings import com.flipperdevices.core.preference.pb.SavedDevice import com.squareup.anvil.annotations.ContributesBinding diff --git a/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt b/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt index cb0225b379..9faf8d39e8 100644 --- a/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt +++ b/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt @@ -5,14 +5,8 @@ import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureQualifier import com.flipperdevices.bridge.connection.feature.common.api.FUnsafeDeviceFeatureApi import com.flipperdevices.bridge.connection.feature.getinfo.api.FGetInfoFeatureApi -import com.flipperdevices.bridge.connection.feature.protocolversion.api.FVersionFeatureApi -import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi -import com.flipperdevices.bridge.connection.transport.common.api.meta.FTransportMetaInfoApi -import com.flipperdevices.core.data.SemVer import com.flipperdevices.core.di.AppGraph -import com.flipperdevices.core.log.error -import com.flipperdevices.core.log.info import com.squareup.anvil.annotations.ContributesMultibinding import kotlinx.coroutines.CoroutineScope import javax.inject.Inject diff --git a/components/nfc/mfkey32/api/build.gradle.kts b/components/nfc/mfkey32/api/build.gradle.kts index 58e1f5efc7..c06955bce7 100644 --- a/components/nfc/mfkey32/api/build.gradle.kts +++ b/components/nfc/mfkey32/api/build.gradle.kts @@ -8,8 +8,6 @@ dependencies { implementation(projects.components.core.ui.decompose) implementation(libs.bundles.decompose) - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.connection.feature.storage.api) implementation(libs.kotlin.coroutines) diff --git a/components/nfc/mfkey32/api/src/main/java/com/flipperdevices/nfc/mfkey32/api/MfKey32Api.kt b/components/nfc/mfkey32/api/src/main/java/com/flipperdevices/nfc/mfkey32/api/MfKey32Api.kt index 46bb1eb336..cb0450440a 100644 --- a/components/nfc/mfkey32/api/src/main/java/com/flipperdevices/nfc/mfkey32/api/MfKey32Api.kt +++ b/components/nfc/mfkey32/api/src/main/java/com/flipperdevices/nfc/mfkey32/api/MfKey32Api.kt @@ -1,6 +1,5 @@ package com.flipperdevices.nfc.mfkey32.api -import com.flipperdevices.bridge.api.manager.FlipperRequestApi import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileStorageMD5Api import kotlinx.coroutines.flow.Flow @@ -14,8 +13,5 @@ interface MfKey32Api { fun hasNotification(): Flow - @Deprecated("Use new api") - suspend fun checkBruteforceFileExist(requestApi: FlipperRequestApi) - suspend fun checkBruteforceFileExist(md5StorageApi: FFileStorageMD5Api) } diff --git a/components/nfc/mfkey32/screen/build.gradle.kts b/components/nfc/mfkey32/screen/build.gradle.kts index b26acd5eac..2a6b5a4475 100644 --- a/components/nfc/mfkey32/screen/build.gradle.kts +++ b/components/nfc/mfkey32/screen/build.gradle.kts @@ -25,11 +25,8 @@ dependencies { implementation(projects.components.core.markdown) implementation(projects.components.core.progress) - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.service.api) - implementation(projects.components.bridge.pbutils) - implementation(projects.components.bridge.rpc.api) - + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.feature.common.api) implementation(projects.components.bridge.connection.feature.storage.api) implementation(projects.components.analytics.metric.api) diff --git a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/api/MfKey32ApiImpl.kt b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/api/MfKey32ApiImpl.kt index 6e848f593b..0d8fb9b1de 100644 --- a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/api/MfKey32ApiImpl.kt +++ b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/api/MfKey32ApiImpl.kt @@ -1,16 +1,11 @@ package com.flipperdevices.nfc.mfkey32.screen.api -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.model.wrapToRequest import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileStorageMD5Api import com.flipperdevices.core.di.AppGraph import com.flipperdevices.nfc.mfkey32.api.MfKey32Api import com.flipperdevices.nfc.mfkey32.screen.viewmodel.PATH_NONCE_LOG -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.storage.md5sumRequest import com.squareup.anvil.annotations.ContributesBinding import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.first import javax.inject.Inject import javax.inject.Singleton @@ -24,26 +19,6 @@ class MfKey32ApiImpl @Inject constructor() : MfKey32Api { private val hasNotificationFlow = MutableStateFlow(false) override fun hasNotification() = hasNotificationFlow - @Deprecated("Use new api") - override suspend fun checkBruteforceFileExist( - requestApi: FlipperRequestApi - ) { - val response = requestApi.request( - main { - storageMd5SumRequest = md5sumRequest { - path = PATH_NONCE_LOG - } - }.wrapToRequest() - ).first() - if (response.hasStorageMd5SumResponse()) { - _isBruteforceFileExist = true - hasNotificationFlow.emit(true) - } else { - _isBruteforceFileExist = false - hasNotificationFlow.emit(false) - } - } - override suspend fun checkBruteforceFileExist(md5StorageApi: FFileStorageMD5Api) { val isMd5Exists = md5StorageApi.md5(PATH_NONCE_LOG).isSuccess _isBruteforceFileExist = isMd5Exists diff --git a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/ExistedKeysStorage.kt b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/ExistedKeysStorage.kt index 43ac14f7f3..21391eeeaf 100644 --- a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/ExistedKeysStorage.kt +++ b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/ExistedKeysStorage.kt @@ -1,33 +1,29 @@ package com.flipperdevices.nfc.mfkey32.screen.viewmodel -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.protobuf.streamToCommandFlow -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi +import com.flipperdevices.bridge.connection.feature.storage.api.exception.FStorageFileNotFoundException +import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileDownloadApi +import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileUploadApi import com.flipperdevices.core.FlipperStorageProvider import com.flipperdevices.core.ktx.jre.withLock import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.error import com.flipperdevices.core.log.info +import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.nfc.mfkey32.screen.model.DuplicatedSource import com.flipperdevices.nfc.mfkey32.screen.model.FoundedInformation import com.flipperdevices.nfc.mfkey32.screen.model.FoundedKey -import com.flipperdevices.protobuf.Flipper -import com.flipperdevices.protobuf.storage.file -import com.flipperdevices.protobuf.storage.writeRequest import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.sync.Mutex +import okio.buffer +import okio.source import java.io.ByteArrayInputStream -import java.io.FileNotFoundException private const val FLIPPER_DICT_USER_PATH = "/ext/nfc/assets/mf_classic_dict_user.nfc" private const val FLIPPER_DICT_PATH = "/ext/nfc/assets/mf_classic_dict.nfc" class ExistedKeysStorage( - private val flipperStorageApi: FlipperStorageApi, private val storageProvider: FlipperStorageProvider ) : LogTagProvider { override val TAG = "ExistedKeysStorage" @@ -40,27 +36,29 @@ class ExistedKeysStorage( fun getFoundedInformation(): StateFlow = foundedInformationStateFlow - suspend fun load() { - val foundedUserDict = loadDict(FLIPPER_DICT_USER_PATH) + suspend fun load(fFileDownloadApi: FFileDownloadApi) { + val foundedUserDict = loadDict(fFileDownloadApi, FLIPPER_DICT_USER_PATH) userDict.addAll(foundedUserDict) userKeys.addAll(foundedUserDict) - val foundedDict = loadDict(FLIPPER_DICT_PATH) + val foundedDict = loadDict(fFileDownloadApi, FLIPPER_DICT_PATH) flipperKeys.addAll(foundedDict) } - suspend fun upload(requestApi: FlipperRequestApi): List { + suspend fun upload(fFileUploadApi: FFileUploadApi): List { val bytesToWrite = userKeys.joinToString(separator = "\n", postfix = "\n").toByteArray() - val response = ByteArrayInputStream(bytesToWrite).use { stream -> - val commandFlow = streamToCommandFlow(stream, bytesToWrite.size.toLong()) { chunkData -> - storageWriteRequest = writeRequest { - path = FLIPPER_DICT_USER_PATH - file = file { data = chunkData } + try { + ByteArrayInputStream(bytesToWrite).source().buffer().use { source -> + fFileUploadApi.sink(FLIPPER_DICT_USER_PATH).use { sink -> + source.copyWithProgress( + sink = sink, + sourceLength = { bytesToWrite.size.toLong() } + ) } } - requestApi.request(commandFlow.map { it.wrapToRequest() }) - } - if (response.commandStatus != Flipper.CommandStatus.OK) { - throw FileNotFoundException() + } catch (e: FStorageFileNotFoundException) { + throw e + } catch (e: Exception) { + error(e) { "#upload Unhandled exception" } } return userKeys.minus(userDict).distinct() } @@ -95,14 +93,14 @@ class ExistedKeysStorage( } } - private suspend fun loadDict(path: String): List { + private suspend fun loadDict(fFileDownloadApi: FFileDownloadApi, path: String): List { return try { storageProvider.useTemporaryFile { tmpFile -> - flipperStorageApi.download( + fFileDownloadApi.download( pathOnFlipper = path, - fileOnAndroid = tmpFile.toFile(), - progressListener = { progress -> - info { "Download dict with progress $progress" } + fileOnAndroid = tmpFile, + progressListener = { current, max -> + info { "Download dict with progress $current/$max" } } ) tmpFile.toFile().readLines() diff --git a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/MfKey32ViewModel.kt b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/MfKey32ViewModel.kt index f201e8b2e1..ea02f722d3 100644 --- a/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/MfKey32ViewModel.kt +++ b/components/nfc/mfkey32/screen/src/main/java/com/flipperdevices/nfc/mfkey32/screen/viewmodel/MfKey32ViewModel.kt @@ -1,12 +1,12 @@ package com.flipperdevices.nfc.mfkey32.screen.viewmodel -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi +import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileDeleteApi +import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileDownloadApi +import com.flipperdevices.bridge.connection.feature.storage.api.fm.FFileStorageMD5Api import com.flipperdevices.core.FlipperStorageProvider import com.flipperdevices.core.ktx.jre.pmap import com.flipperdevices.core.log.LogTagProvider @@ -23,20 +23,14 @@ import com.flipperdevices.nfc.mfkey32.screen.model.FoundedKey import com.flipperdevices.nfc.mfkey32.screen.model.MfKey32State import com.flipperdevices.nfc.tools.api.MfKey32Nonce import com.flipperdevices.nfc.tools.api.NfcToolsApi -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.storage.deleteRequest import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.Job import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock +import okio.Path.Companion.toOkioPath import java.math.BigInteger import java.util.concurrent.Executors import javax.inject.Inject @@ -48,10 +42,9 @@ class MfKey32ViewModel @Inject constructor( private val nfcToolsApi: NfcToolsApi, private val mfKey32Api: MfKey32Api, private val metricApi: MetricApi, - flipperServiceProvider: FlipperServiceProvider, - private val flipperStorageApi: FlipperStorageApi, + private val fFeatureProvider: FFeatureProvider, storageProvider: FlipperStorageProvider -) : DecomposeViewModel(), LogTagProvider, FlipperBleServiceConsumer { +) : DecomposeViewModel(), LogTagProvider { override val TAG = "MfKey32ViewModel" private val bruteforceDispatcher = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() @@ -60,62 +53,43 @@ class MfKey32ViewModel @Inject constructor( MfKey32State.Error(ErrorType.FLIPPER_CONNECTION) ) - private val existedKeysStorage = ExistedKeysStorage(flipperStorageApi, storageProvider) + private val existedKeysStorage = ExistedKeysStorage(storageProvider) private val fileWithNonce by lazy { storageProvider.getTemporaryFile().toFile() } - private var stateJob: Job? = null - private val mutex = Mutex() - - init { - flipperServiceProvider.provideServiceApi(this, this) - } fun getMfKey32State(): StateFlow = mfKey32StateFlow fun getFoundedInformation(): StateFlow = existedKeysStorage.getFoundedInformation() - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - viewModelScope.launch { - mutex.withLock { - val localJob = stateJob - stateJob = viewModelScope.launch { - localJob?.cancelAndJoin() - serviceApi - .connectionInformationApi - .getConnectionStateFlow() - .collectLatest { connectionState -> - startCalculation(serviceApi, connectionState) - } - } - } - } + init { + fFeatureProvider + .get() + .onEach { status -> startCalculation(status) } + .launchIn(viewModelScope) } - private suspend fun startCalculation( - serviceApi: FlipperServiceApi, - connectionState: ConnectionState - ) { - info { "Start calculation on $connectionState" } + private suspend fun startCalculation(status: FFeatureStatus) { + info { "Start calculation on $status" } - when (connectionState) { - ConnectionState.Connecting, - ConnectionState.Disconnecting, - ConnectionState.RetrievingInformation, - ConnectionState.Initializing -> { - mfKey32StateFlow.emit(MfKey32State.WaitingForFlipper) + val featureApi = when (status) { + FFeatureStatus.Unsupported, + FFeatureStatus.NotFound -> { + mfKey32StateFlow.emit(MfKey32State.Error(ErrorType.FLIPPER_CONNECTION)) return } - is ConnectionState.Disconnected -> { - mfKey32StateFlow.emit(MfKey32State.Error(ErrorType.FLIPPER_CONNECTION)) + FFeatureStatus.Retrieving -> { + mfKey32StateFlow.emit(MfKey32State.WaitingForFlipper) return } - is ConnectionState.Ready -> {} + is FFeatureStatus.Supported -> { + status.featureApi + } } - if (!prepare(serviceApi)) { + if (!prepare(featureApi.downloadApi(), featureApi.md5Api())) { info { "Failed prepare" } return } @@ -129,17 +103,23 @@ class MfKey32ViewModel @Inject constructor( } mfKey32StateFlow.emit(MfKey32State.Uploading) val addedKeys = try { - existedKeysStorage.upload(serviceApi.requestApi) + existedKeysStorage.upload(featureApi.uploadApi()) } catch (exception: Throwable) { error(exception) { "When save keys" } mfKey32StateFlow.emit(MfKey32State.Error(ErrorType.READ_WRITE)) return } - deleteBruteforceApp(serviceApi.requestApi) + deleteBruteforceApp( + deleteApi = featureApi.deleteApi(), + md5Api = featureApi.md5Api() + ) mfKey32StateFlow.emit(MfKey32State.Saved(addedKeys.toImmutableList())) } - private suspend fun prepare(serviceApi: FlipperServiceApi): Boolean { + private suspend fun prepare( + fFileDownloadApi: FFileDownloadApi, + md5Api: FFileStorageMD5Api + ): Boolean { info { "Flipper connected" } if (!mfKey32Api.isBruteforceFileExist) { @@ -147,7 +127,7 @@ class MfKey32ViewModel @Inject constructor( mfKey32StateFlow.emit(MfKey32State.Error(ErrorType.NOT_FOUND_FILE)) } - mfKey32Api.checkBruteforceFileExist(serviceApi.requestApi) + mfKey32Api.checkBruteforceFileExist(md5Api) if (!mfKey32Api.isBruteforceFileExist) { return false @@ -156,9 +136,9 @@ class MfKey32ViewModel @Inject constructor( mfKey32StateFlow.emit(MfKey32State.DownloadingRawFile(0f)) try { - flipperStorageApi.download( + fFileDownloadApi.download( pathOnFlipper = PATH_NONCE_LOG, - fileOnAndroid = fileWithNonce, + fileOnAndroid = fileWithNonce.toOkioPath(), progressListener = ProgressWrapperTracker( progressListener = { progress -> info { "Download file progress $progress" } @@ -174,7 +154,7 @@ class MfKey32ViewModel @Inject constructor( } metricApi.reportSimpleEvent(SimpleEvent.MFKEY32) try { - existedKeysStorage.load() + existedKeysStorage.load(fFileDownloadApi) } catch (exception: Throwable) { error(exception) { "When load keys" } mfKey32StateFlow.emit(MfKey32State.Error(ErrorType.READ_WRITE)) @@ -185,15 +165,13 @@ class MfKey32ViewModel @Inject constructor( return true } - private suspend fun deleteBruteforceApp(requestApi: FlipperRequestApi) { - requestApi.request( - main { - storageDeleteRequest = deleteRequest { - path = PATH_NONCE_LOG - } - }.wrapToRequest() - ).collect() - mfKey32Api.checkBruteforceFileExist(requestApi) + private suspend fun deleteBruteforceApp( + deleteApi: FFileDeleteApi, + md5Api: FFileStorageMD5Api + ) { + deleteApi.delete(path = PATH_NONCE_LOG) + .onFailure { error(it) { "#deleteBruteforceApp could not delete " } } + mfKey32Api.checkBruteforceFileExist(md5Api) } private suspend fun onFoundKey(nonce: MfKey32Nonce, key: BigInteger?, totalCount: Int) {