From 1f606ae19fdedf936bf0111e662bff27938f6e8c Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Tue, 17 Dec 2024 12:55:21 +0300 Subject: [PATCH 1/7] convert target module into new api --- .../utils/FZeroFeatureClassToEnumMapper.kt | 2 + .../feature/common/api/FDeviceFeature.kt | 1 + .../api/FSdkVersionFeatureApi.kt | 8 +++ .../protocolversion/impl/build.gradle.kts | 4 ++ .../impl/api/FSdkVersionFeatureApiImpl.kt | 66 ++++++++++++++++++ .../impl/api/FSdkVersionFeatureFactoryImpl.kt | 46 +++++++++++++ .../faphub/target/impl/build.gradle.kts | 8 +-- .../impl/api/FlipperTargetProviderApiImpl.kt | 67 ++++++++++++------- .../target/impl/model/FlipperSdkVersion.kt | 10 --- .../target/impl/utils/FlipperSdkFetcher.kt | 63 ----------------- 10 files changed, 172 insertions(+), 103 deletions(-) create mode 100644 components/bridge/connection/feature/protocolversion/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/api/FSdkVersionFeatureApi.kt create mode 100644 components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureApiImpl.kt create mode 100644 components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt delete mode 100644 components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/model/FlipperSdkVersion.kt delete mode 100644 components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/utils/FlipperSdkFetcher.kt diff --git a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt index e6afff3bc2..ca9b4bb7bf 100644 --- a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt +++ b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt @@ -6,6 +6,7 @@ import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi import com.flipperdevices.bridge.connection.feature.devicecolor.api.FDeviceColorFeatureApi import com.flipperdevices.bridge.connection.feature.getinfo.api.FGattInfoFeatureApi import com.flipperdevices.bridge.connection.feature.getinfo.api.FGetInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.protocolversion.api.FSdkVersionFeatureApi import com.flipperdevices.bridge.connection.feature.protocolversion.api.FVersionFeatureApi import com.flipperdevices.bridge.connection.feature.restartrpc.api.FRestartRpcFeatureApi import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi @@ -36,6 +37,7 @@ object FZeroFeatureClassToEnumMapper { FDeviceFeature.ALARM -> FAlarmFeatureApi::class FDeviceFeature.DEVICE_COLOR -> FDeviceColorFeatureApi::class FDeviceFeature.GATT_INFO -> FGattInfoFeatureApi::class + FDeviceFeature.SDK_VERSION -> FSdkVersionFeatureApi::class } } diff --git a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt index c1a7344462..7509891994 100644 --- a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt +++ b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt @@ -15,6 +15,7 @@ enum class FDeviceFeature { ALARM, DEVICE_COLOR, GATT_INFO, + SDK_VERSION } @Retention(AnnotationRetention.RUNTIME) diff --git a/components/bridge/connection/feature/protocolversion/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/api/FSdkVersionFeatureApi.kt b/components/bridge/connection/feature/protocolversion/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/api/FSdkVersionFeatureApi.kt new file mode 100644 index 0000000000..44673d84ab --- /dev/null +++ b/components/bridge/connection/feature/protocolversion/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/api/FSdkVersionFeatureApi.kt @@ -0,0 +1,8 @@ +package com.flipperdevices.bridge.connection.feature.protocolversion.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.core.data.SemVer + +interface FSdkVersionFeatureApi : FDeviceFeatureApi { + suspend fun getSdkVersion(): Result +} diff --git a/components/bridge/connection/feature/protocolversion/impl/build.gradle.kts b/components/bridge/connection/feature/protocolversion/impl/build.gradle.kts index 445b61c1de..7cbbcae2d3 100644 --- a/components/bridge/connection/feature/protocolversion/impl/build.gradle.kts +++ b/components/bridge/connection/feature/protocolversion/impl/build.gradle.kts @@ -8,6 +8,10 @@ android.namespace = "com.flipperdevices.bridge.connection.feature.protocolversio commonDependencies { implementation(projects.components.bridge.connection.feature.protocolversion.api) + implementation(projects.components.bridge.connection.feature.rpc.api) + implementation(projects.components.bridge.connection.feature.rpc.model) + + implementation(projects.components.bridge.connection.pbutils) implementation(projects.components.core.di) implementation(projects.components.core.data) diff --git a/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureApiImpl.kt b/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureApiImpl.kt new file mode 100644 index 0000000000..745386575a --- /dev/null +++ b/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureApiImpl.kt @@ -0,0 +1,66 @@ +package com.flipperdevices.bridge.connection.feature.protocolversion.impl.api + +import com.flipperdevices.bridge.connection.feature.protocolversion.api.FSdkVersionFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.model.wrapToRequest +import com.flipperdevices.core.data.SemVer +import com.flipperdevices.core.log.info +import com.flipperdevices.protobuf.Main +import com.flipperdevices.protobuf.property.GetRequest +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.toList + +class FSdkVersionFeatureApiImpl @AssistedInject constructor( + @Assisted private val rpcFeatureApi: FRpcFeatureApi, +) : FSdkVersionFeatureApi { + + override suspend fun getSdkVersion(): Result = runCatching { + val answers = rpcFeatureApi.request( + Main( + property_get_request = GetRequest( + key = RPC_SDK_KEY + ) + ).wrapToRequest() + ).toList() + info { "Receive ${answers.size} answers by $RPC_SDK_KEY, $answers" } + val major = answers + .firstOrNull { result -> + result.getOrNull()?.property_get_response?.key == RPC_SDK_MAJOR_KEY + } + ?.getOrNull()?.property_get_response + ?.value_ + ?.toIntOrNull() + ?: error("Answer doesn't contains $RPC_SDK_MAJOR_KEY") + + val minor = answers + .firstOrNull { result -> + result.getOrNull()?.property_get_response?.key == RPC_SDK_MINOR_KEY + } + ?.getOrNull()?.property_get_response + ?.value_ + ?.toIntOrNull() + ?: error("Answer doesn't contains $RPC_SDK_MINOR_KEY") + + info { "Receive version $major and $minor" } + + SemVer( + majorVersion = major, + minorVersion = minor + ) + } + + @AssistedFactory + fun interface InternalFactory { + operator fun invoke( + rpcFeatureApi: FRpcFeatureApi, + ): FSdkVersionFeatureApiImpl + } + + companion object { + private const val RPC_SDK_KEY = "devinfo.firmware.api" + private const val RPC_SDK_MAJOR_KEY = "firmware.api.major" + private const val RPC_SDK_MINOR_KEY = "firmware.api.minor" + } +} 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 new file mode 100644 index 0000000000..eb7212d11f --- /dev/null +++ b/components/bridge/connection/feature/protocolversion/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/protocolversion/impl/api/FSdkVersionFeatureFactoryImpl.kt @@ -0,0 +1,46 @@ +package com.flipperdevices.bridge.connection.feature.protocolversion.impl.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature +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.protocolversion.api.FVersionFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi +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 + +// todo move to shared const +private val API_SUPPORTED_GET_REQUEST = SemVer( + majorVersion = 0, + minorVersion = 14 +) + +@FDeviceFeatureQualifier(FDeviceFeature.SDK_VERSION) +@ContributesMultibinding(AppGraph::class, FDeviceFeatureApi.Factory::class) +class FSdkVersionFeatureFactoryImpl @Inject constructor( + private val factory: FSdkVersionFeatureApiImpl.InternalFactory +) : FDeviceFeatureApi.Factory { + override suspend fun invoke( + unsafeFeatureDeviceApi: FUnsafeDeviceFeatureApi, + scope: CoroutineScope, + connectedDevice: FConnectedDeviceApi + ): FDeviceFeatureApi? { + val versionApi = unsafeFeatureDeviceApi.getUnsafe(FVersionFeatureApi::class) ?: return null + info { "Start request supported state for api level $API_SUPPORTED_GET_REQUEST" } + val isSupported = versionApi.isSupported(API_SUPPORTED_GET_REQUEST) + if (!isSupported) { + error { "Failed init FDeviceColorFeatureApi, because isSupported=false" } + return null + } + val rpcApi = unsafeFeatureDeviceApi.getUnsafe(FRpcFeatureApi::class) ?: return null + return factory( + rpcFeatureApi = rpcApi + ) + } +} diff --git a/components/faphub/target/impl/build.gradle.kts b/components/faphub/target/impl/build.gradle.kts index ea3255c1e1..fc1110effe 100644 --- a/components/faphub/target/impl/build.gradle.kts +++ b/components/faphub/target/impl/build.gradle.kts @@ -13,10 +13,10 @@ dependencies { implementation(projects.components.core.log) implementation(projects.components.core.data) - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.pbutils) - implementation(projects.components.bridge.service.api) - implementation(projects.components.bridge.rpcinfo.api) + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.orchestrator.api) + implementation(projects.components.bridge.connection.feature.protocolversion.api) implementation(projects.components.faphub.utils) diff --git a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt index f3b59bd59b..be6225b2ec 100644 --- a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt +++ b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt @@ -1,14 +1,16 @@ package com.flipperdevices.faphub.target.impl.api -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.protocolversion.api.FSdkVersionFeatureApi +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.orchestrator.api.FDeviceOrchestrator +import com.flipperdevices.bridge.connection.orchestrator.api.model.FDeviceConnectStatus import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.info import com.flipperdevices.faphub.target.api.FlipperTargetProviderApi -import com.flipperdevices.faphub.target.impl.model.FlipperSdkVersion -import com.flipperdevices.faphub.target.impl.utils.FlipperSdkFetcher import com.flipperdevices.faphub.target.model.FlipperTarget import com.squareup.anvil.annotations.ContributesBinding import kotlinx.coroutines.CoroutineScope @@ -24,8 +26,8 @@ import javax.inject.Singleton @Singleton @ContributesBinding(AppGraph::class, FlipperTargetProviderApi::class) class FlipperTargetProviderApiImpl @Inject constructor( - private val serviceProvider: FlipperServiceProvider, - private val fetcher: FlipperSdkFetcher + private val fFeatureProviderApi: FFeatureProvider, + private val fDeviceOrchestrator: FDeviceOrchestrator ) : FlipperTargetProviderApi, LogTagProvider { override val TAG = "FlipperTargetProviderApi" @@ -42,34 +44,47 @@ class FlipperTargetProviderApiImpl @Inject constructor( private suspend fun subscribe() { info { "Start subscribe" } - val serviceApi = serviceProvider.getServiceApi() + combine( - serviceApi.connectionInformationApi.getConnectionStateFlow(), - serviceApi.flipperVersionApi.getVersionInformationFlow() - ) { connectionState, version -> - if (!connectionState.isConnected) { - when (connectionState) { - is ConnectionState.Disconnected -> targetFlow.emit(FlipperTarget.NotConnected) - else -> targetFlow.emit(null) + fDeviceOrchestrator.getState(), + fFeatureProviderApi.get() + ) { connectionState, status -> + when (connectionState) { + is FDeviceConnectStatus.Disconnecting, + is FDeviceConnectStatus.Disconnected, + is FDeviceConnectStatus.Connecting -> { + targetFlow.emit(FlipperTarget.NotConnected) + return@combine } - return@combine + + is FDeviceConnectStatus.Connected -> Unit } + targetFlow.emit(null) - info { "Receive version $version" } - val sdkVersion = fetcher.getSdkApi(serviceApi.requestApi, version) - info { "Sdk version is $sdkVersion" } - val newTargetState = when (sdkVersion) { - FlipperSdkVersion.Unsupported, - FlipperSdkVersion.Error -> FlipperTarget.Unsupported + val semVer = when (status) { + is FFeatureStatus.Supported -> status.featureApi.getSdkVersion().getOrNull() + + FFeatureStatus.Retrieving -> { + targetFlow.emit(FlipperTarget.NotConnected) + return@combine + } + + FFeatureStatus.NotFound, + FFeatureStatus.Unsupported -> { + targetFlow.emit(FlipperTarget.NotConnected) + return@combine + } + } + info { "Sdk version is $semVer" } - FlipperSdkVersion.InProgress -> null - is FlipperSdkVersion.Received -> FlipperTarget.Received( + val targetState = when (semVer) { + null -> null + else -> FlipperTarget.Received( target = "f7", - sdk = sdkVersion.sdk + sdk = semVer ) } - info { "New target state is $newTargetState" } - targetFlow.emit(newTargetState) + targetFlow.emit(targetState) }.collect() } } diff --git a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/model/FlipperSdkVersion.kt b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/model/FlipperSdkVersion.kt deleted file mode 100644 index 17f88fadad..0000000000 --- a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/model/FlipperSdkVersion.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.flipperdevices.faphub.target.impl.model - -import com.flipperdevices.core.data.SemVer - -sealed class FlipperSdkVersion { - object InProgress : FlipperSdkVersion() - object Unsupported : FlipperSdkVersion() - object Error : FlipperSdkVersion() - data class Received(val sdk: SemVer) : FlipperSdkVersion() -} diff --git a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/utils/FlipperSdkFetcher.kt b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/utils/FlipperSdkFetcher.kt deleted file mode 100644 index 6bbf6b52c2..0000000000 --- a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/utils/FlipperSdkFetcher.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.flipperdevices.faphub.target.impl.utils - -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.core.data.SemVer -import com.flipperdevices.core.log.LogTagProvider -import com.flipperdevices.core.log.info -import com.flipperdevices.faphub.target.impl.model.FlipperSdkVersion -import com.flipperdevices.faphub.utils.FapHubConstants -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.property.getRequest -import kotlinx.coroutines.flow.toList -import javax.inject.Inject - -private const val RPC_SDK_KEY = "devinfo.firmware.api" -private const val RPC_SDK_MAJOR_KEY = "firmware.api.major" -private const val RPC_SDK_MINOR_KEY = "firmware.api.minor" - -class FlipperSdkFetcher @Inject constructor() : LogTagProvider { - override val TAG = "FlipperSdkFetcher" - suspend fun getSdkApi( - requestApi: FlipperRequestApi, - currentVersion: SemVer? - ): FlipperSdkVersion { - if (currentVersion == null) { - info { "Don't receive version, skip" } - return FlipperSdkVersion.InProgress - } else if (currentVersion < FapHubConstants.RPC_SUPPORTED_VERSION) { - info { - "Current version RPC is outdated ($currentVersion). " + - "Need ${FapHubConstants.RPC_SUPPORTED_VERSION}" - } - return FlipperSdkVersion.Unsupported - } - - val answers = requestApi.request( - main { - propertyGetRequest = getRequest { - key = RPC_SDK_KEY - } - }.wrapToRequest() - ).toList() - info { "Receive ${answers.size} answers by $RPC_SDK_KEY, $answers" } - - val major = answers.find { - it.hasPropertyGetResponse() && - it.propertyGetResponse.key == RPC_SDK_MAJOR_KEY - }?.propertyGetResponse?.value?.toIntOrNull() ?: return FlipperSdkVersion.Error - val minor = answers.find { - it.hasPropertyGetResponse() && - it.propertyGetResponse.key == RPC_SDK_MINOR_KEY - }?.propertyGetResponse?.value?.toIntOrNull() ?: return FlipperSdkVersion.Error - - info { "Receive version $major and $minor" } - - return FlipperSdkVersion.Received( - SemVer( - majorVersion = major, - minorVersion = minor - ) - ) - } -} From af26a920a6c562675f513a128c16cf2b8a7c3e0e Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Tue, 17 Dec 2024 15:02:35 +0300 Subject: [PATCH 2/7] convert manifest module into new api --- .../manifest/error/NoSdCardException.kt | 3 + .../manifest/impl/build.gradle.kts | 20 +++- .../manifest/impl/utils/FapExistChecker.kt | 19 ++-- .../impl/utils/FapManifestAtomicMover.kt | 91 ++++++++---------- .../impl/utils/FapManifestCacheLoader.kt | 22 +++-- .../manifest/impl/utils/FapManifestDeleter.kt | 23 ++++- .../impl/utils/FapManifestUploader.kt | 40 ++++---- .../manifest/impl/utils/FapManifestsLoader.kt | 92 +++++++++---------- 8 files changed, 160 insertions(+), 150 deletions(-) create mode 100644 components/faphub/installation/manifest/api/src/main/java/com/flipperdevices/faphub/installation/manifest/error/NoSdCardException.kt diff --git a/components/faphub/installation/manifest/api/src/main/java/com/flipperdevices/faphub/installation/manifest/error/NoSdCardException.kt b/components/faphub/installation/manifest/api/src/main/java/com/flipperdevices/faphub/installation/manifest/error/NoSdCardException.kt new file mode 100644 index 0000000000..f7fe18ecff --- /dev/null +++ b/components/faphub/installation/manifest/api/src/main/java/com/flipperdevices/faphub/installation/manifest/error/NoSdCardException.kt @@ -0,0 +1,3 @@ +package com.flipperdevices.faphub.installation.manifest.error + +class NoSdCardException : RuntimeException() diff --git a/components/faphub/installation/manifest/impl/build.gradle.kts b/components/faphub/installation/manifest/impl/build.gradle.kts index e2471b0cda..8cb08ee260 100644 --- a/components/faphub/installation/manifest/impl/build.gradle.kts +++ b/components/faphub/installation/manifest/impl/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { implementation(projects.components.core.data) implementation(projects.components.core.log) implementation(projects.components.core.preference) + implementation(projects.components.core.progress) implementation(projects.components.settings.api) @@ -20,13 +21,22 @@ dependencies { implementation(projects.components.faphub.utils) implementation(projects.components.faphub.errors.api) - implementation(projects.components.bridge.api) + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.feature.storage.api) + implementation(projects.components.bridge.connection.feature.protocolversion.api) + implementation(projects.components.bridge.connection.feature.storageinfo.api) + implementation(projects.components.bridge.connection.orchestrator.api) + +// implementation(projects.components.bridge.api) implementation(projects.components.bridge.dao.api) - implementation(projects.components.bridge.rpc.api) - implementation(projects.components.bridge.rpcinfo.api) - implementation(projects.components.bridge.service.api) - implementation(projects.components.bridge.pbutils) +// implementation(projects.components.bridge.rpc.api) +// implementation(projects.components.bridge.rpcinfo.api) +// implementation(projects.components.bridge.service.api) +// implementation(projects.components.bridge.pbutils) implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) + implementation(libs.okio) } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt index 39d87779e0..55079d4715 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt @@ -1,6 +1,8 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi import com.flipperdevices.core.ktx.jre.withLock import com.flipperdevices.core.ktx.jre.withLockResult import com.flipperdevices.core.log.LogTagProvider @@ -10,7 +12,7 @@ import kotlin.io.path.Path import kotlin.io.path.pathString class FapExistChecker @Inject constructor( - private val flipperStorageApi: FlipperStorageApi + private val fFeatureProvider: FFeatureProvider ) : LogTagProvider { override val TAG = "FapExistChecker" @@ -19,12 +21,15 @@ class FapExistChecker @Inject constructor( suspend fun checkExist(path: String): Boolean = withLockResult(mutex, "check") { val folder = Path(path).parent?.pathString ?: "/" + val fileList = cacheFolderToPaths[folder] - ?: flipperStorageApi.listingDirectory(folder) - .map { name -> Path(folder, name).pathString } - .also { - cacheFolderToPaths[folder] = it - } + ?: fFeatureProvider.getSync() + ?.listingApi() + ?.ls(folder) + ?.getOrNull() + .orEmpty() + .map { item-> Path(folder).resolve(item.fileName).toString() } + .also { paths -> cacheFolderToPaths[folder] = paths } return@withLockResult fileList.contains(path) } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt index 5bf060d981..d5b37292bb 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt @@ -1,78 +1,61 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils -import com.flipperdevices.bridge.api.manager.service.FlipperVersionApi -import com.flipperdevices.bridge.api.model.FlipperRequest -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.protocolversion.api.FVersionFeatureApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi import com.flipperdevices.core.data.SemVer -import com.flipperdevices.protobuf.Flipper -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.storage.deleteRequest -import com.flipperdevices.protobuf.storage.renameRequest +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext +import okio.Path +import okio.Path.Companion.toPath import java.io.File import javax.inject.Inject private val UNIX_MV_SUPPORTED_VERSION_API = SemVer(majorVersion = 0, minorVersion = 17) class FapManifestAtomicMover @Inject constructor( - private val flipperServiceProvider: FlipperServiceProvider, - private val flipperStorageApi: FlipperStorageApi -) { + private val fFeatureProvider: FFeatureProvider +) : LogTagProvider { + override val TAG: String = "FapManifestAtomicMover" suspend fun atomicMove( vararg fromToPair: Pair ) { - val serviceApi = flipperServiceProvider.getServiceApi() - fromToPair.mapNotNull { (_, to) -> File(to).parent }.forEach { - flipperStorageApi.mkdirs(it) + val fSemVer = fFeatureProvider.getSync() + ?.getVersionInformationFlow() + ?.first() + + val fStorageFeatureApi = fFeatureProvider.getSync() + if (fStorageFeatureApi == null) { + error { "#atomicMove could not find FStorageFeatureApi" } + return } - val preparedRequest = getPrepareRequests( - serviceApi.flipperVersionApi, - fromToPair.map { it.second } - ) - val moveRequests = getRequests(fromToPair) + fromToPair.mapNotNull { (_, to) -> File(to).parent } + .forEach { fullPath -> fStorageFeatureApi.uploadApi().mkdir(fullPath) } + + val deleteTargets = fromToPair.map { pair -> pair.second } + withContext(NonCancellable) { - @Suppress("SpreadOperator") - serviceApi.requestApi.requestWithoutAnswer(*preparedRequest.toTypedArray()) - moveRequests.map { - serviceApi.requestApi.request(it) - }.map { it.first() }.forEach { response -> - if (response.commandStatus != Flipper.CommandStatus.OK) { - error("Failed move path, failed response: $response") + if (fSemVer == null || fSemVer < UNIX_MV_SUPPORTED_VERSION_API) { + deleteTargets.map { target -> + fStorageFeatureApi.deleteApi().delete(target) } } - } - } - private suspend fun getPrepareRequests( - versionApi: FlipperVersionApi, - targets: List - ): List { - val version = versionApi.getVersionInformationFlow().first() - if (version != null && version >= UNIX_MV_SUPPORTED_VERSION_API) { - return emptyList() - } - return targets.map { target -> - main { - storageDeleteRequest = deleteRequest { - path = target - } - }.wrapToRequest() - } - } - - private fun getRequests( - fromToPair: Array> - ) = fromToPair.map { (from, to) -> - main { - storageRenameRequest = renameRequest { - oldPath = from - newPath = to + fromToPair.map { (from, to) -> + fStorageFeatureApi.uploadApi().move( + oldPath = from.toPath(), + newPath = to.toPath() + ) + }.onEach { result -> + result + .onFailure { error(it) { "Failed move path" } } + .getOrThrow() } - }.wrapToRequest() + } } } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt index 317a94c40f..b22a12304b 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt @@ -1,7 +1,9 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils import android.content.Context -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.ktx.jre.md5 import com.flipperdevices.core.ktx.jre.withLock @@ -11,6 +13,7 @@ import com.flipperdevices.core.log.info import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext +import okio.Path import java.io.File import javax.inject.Inject import javax.inject.Singleton @@ -23,7 +26,7 @@ data class FapManifestCacheLoadResult( @Singleton class FapManifestCacheLoader @Inject constructor( context: Context, - private val flipperStorageApi: FlipperStorageApi, + private val fFeatureProvider: FFeatureProvider, private val parser: FapManifestParser ) : LogTagProvider { private val cacheDir = File(context.cacheDir, "fap_manifests") @@ -31,10 +34,14 @@ class FapManifestCacheLoader @Inject constructor( override val TAG = "FapManifestCacheLoader" suspend fun loadCache(): FapManifestCacheLoadResult = withLockResult(mutex, "load") { - val namesWithHash = flipperStorageApi - .listingDirectoryWithMd5(FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER) - .filter { File(it.name).extension == FapManifestConstants.FAP_MANIFEST_EXTENSION } - .filterNot { it.name.startsWith(".") } + val namesWithHash = fFeatureProvider.getSync() + ?.listingApi() + ?.lsWithMd5(FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER) + ?.getOrNull() + .orEmpty() + .filter { item -> File(item.fileName).extension == FapManifestConstants.FAP_MANIFEST_EXTENSION } + .filterNot { item -> item.fileName.startsWith(".") } + .map { item -> item.fileName to item.md5 } val filesWithHash = getLocalFilesWithHash().associate { (file, md5) -> md5 to file } info { "Find ${filesWithHash.size} files in cache" } val cached = mutableListOf>() @@ -67,7 +74,8 @@ class FapManifestCacheLoader @Inject constructor( .toMutableMap() val toDeleteFiles = HashSet(existedFiles.map { it.value }) for (manifest in manifestItems) { - val manifestHash = manifest.sourceFileHash ?: parser.encode(manifest).openStream().md5() + val manifestHash = + manifest.sourceFileHash ?: parser.encode(manifest).openStream().md5() val existedFile = existedFiles[manifestHash] if (existedFile != null) { toDeleteFiles.remove(existedFile) diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestDeleter.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestDeleter.kt index 5c1c9f941d..731f9b143b 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestDeleter.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestDeleter.kt @@ -1,19 +1,32 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem import java.io.File import javax.inject.Inject class FapManifestDeleter @Inject constructor( - private val flipperStorageApi: FlipperStorageApi -) { + private val fFeatureProvider: FFeatureProvider +) : LogTagProvider { + override val TAG: String = "FapManifestDeleter" + suspend fun delete(fapManifestItem: FapManifestItem) { val manifestPath = File( FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER, "${fapManifestItem.applicationAlias}.${FapManifestConstants.FAP_MANIFEST_EXTENSION}" ).path - flipperStorageApi.delete(manifestPath) - flipperStorageApi.delete(fapManifestItem.path) + val deleteApi = fFeatureProvider.getSync()?.deleteApi() + if (deleteApi == null) { + error { "#delete could not getSync deleteApi" } + return + } + deleteApi.delete(manifestPath) + .onFailure { error(it) { "#delete could not delete $manifestPath" } } + deleteApi.delete(fapManifestItem.path) + .onFailure { error(it) { "#delete could not delete ${fapManifestItem.path}" } } } } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt index d29142ebb4..3e11769532 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt @@ -1,25 +1,24 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.protobuf.streamToCommandFlow -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.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi 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.faphub.installation.manifest.impl.utils.FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER import com.flipperdevices.faphub.installation.manifest.impl.utils.FapManifestConstants.FAP_MANIFEST_EXTENSION import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem import com.flipperdevices.faphub.utils.FapHubTmpFolderProvider -import com.flipperdevices.protobuf.Flipper -import com.flipperdevices.protobuf.storage.file -import com.flipperdevices.protobuf.storage.writeRequest -import kotlinx.coroutines.flow.map +import okio.buffer +import okio.source import java.io.File import javax.inject.Inject class FapManifestUploader @Inject constructor( private val parser: FapManifestParser, - private val flipperServiceProvider: FlipperServiceProvider, + private val fFeatureProvider: FFeatureProvider, private val atomicMover: FapManifestAtomicMover, private val tmpFolderProvider: FapHubTmpFolderProvider ) : LogTagProvider { @@ -42,35 +41,30 @@ class FapManifestUploader @Inject constructor( private suspend fun saveToTmp(fapManifestItem: FapManifestItem): String { info { "Start save tmp manifest for ${fapManifestItem.applicationAlias}" } - val serviceApi = flipperServiceProvider.getServiceApi() val tmpFapPath = File( tmpFolderProvider.provideTmpFolder(), "tmp.fim" ).path - uploadTmpManifest(serviceApi.requestApi, fapManifestItem, tmpFapPath) + uploadTmpManifest(fapManifestItem, tmpFapPath) info { "Finish tmp manifest upload, path is $tmpFapPath" } return tmpFapPath } private suspend fun uploadTmpManifest( - requestApi: FlipperRequestApi, fapManifestItem: FapManifestItem, fapPath: String ) { val fff = parser.encode(fapManifestItem) - val response = fff.openStream().use { inputStream -> - val requestFlow = streamToCommandFlow(inputStream, fff.length()) { chunkData -> - storageWriteRequest = writeRequest { - path = fapPath - file = file { data = chunkData } - } - }.map { it.wrapToRequest() } - requestApi.request(requestFlow) + val uploadApi = fFeatureProvider.getSync()?.uploadApi() + if (uploadApi == null) { + error { "#uploadTmpManifest could not find uploadApi" } + return } - - if (response.commandStatus != Flipper.CommandStatus.OK) { - error("Failed upload tmp manifest") + fff.openStream().use { inputStream -> + uploadApi.sink(pathOnFlipper = fapPath) + .buffer() + .use { sink -> inputStream.source().copyWithProgress(sink) } } } } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt index c7dfcccf4a..59856242ad 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt @@ -1,27 +1,27 @@ package com.flipperdevices.faphub.installation.manifest.impl.utils import androidx.datastore.core.DataStore -import com.flipperdevices.bridge.api.manager.FlipperRequestApi -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.api.model.FlipperRequestPriority -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.rpc.api.model.exceptions.NoSdCardException -import com.flipperdevices.bridge.rpcinfo.api.FlipperStorageInformationApi -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.rpcinfo.model.FlipperStorageInformation -import com.flipperdevices.bridge.rpcinfo.model.StorageStats -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.getSync +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi +import com.flipperdevices.bridge.connection.feature.storage.api.model.StorageRequestPriority +import com.flipperdevices.bridge.connection.feature.storageinfo.api.FStorageInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.storageinfo.model.FlipperStorageInformation +import com.flipperdevices.bridge.connection.feature.storageinfo.model.StorageStats +import com.flipperdevices.bridge.connection.orchestrator.api.FDeviceOrchestrator +import com.flipperdevices.bridge.connection.orchestrator.api.model.FDeviceConnectStatus import com.flipperdevices.core.ktx.jre.flatten import com.flipperdevices.core.ktx.jre.launchWithLock import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import com.flipperdevices.core.log.info import com.flipperdevices.core.preference.pb.Settings import com.flipperdevices.faphub.errors.api.throwable.FlipperNotConnected +import com.flipperdevices.faphub.installation.manifest.error.NoSdCardException import com.flipperdevices.faphub.installation.manifest.impl.model.FapManifestLoaderState import com.flipperdevices.faphub.installation.manifest.impl.utils.FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.storage.readRequest import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -31,6 +31,7 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest @@ -39,17 +40,18 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex +import okio.buffer import java.io.File @Suppress("LongParameterList") class FapManifestsLoader @AssistedInject constructor( @Assisted private val scope: CoroutineScope, - private val flipperServiceProvider: FlipperServiceProvider, private val parser: FapManifestParser, private val dataStoreSettings: DataStore, private val cacheLoader: FapManifestCacheLoader, - private val flipperStorageInformationApi: FlipperStorageInformationApi, - private val fapExistChecker: FapExistChecker + private val fapExistChecker: FapExistChecker, + private val fFeatureProvider: FFeatureProvider, + private val fDeviceOrchestrator: FDeviceOrchestrator ) : LogTagProvider { override val TAG = "FapManifestsLoader" private val manifestLoaderState = MutableStateFlow( @@ -73,16 +75,16 @@ class FapManifestsLoader @AssistedInject constructor( isLoading = true ) ) - val serviceApi = flipperServiceProvider.getServiceApi() - flipperStorageInformationApi.invalidate( - scope = scope, - serviceApi = serviceApi - ) + val fStorageInfoApi = fFeatureProvider.getSync() + if (fStorageInfoApi == null) { + error { "#invalidate could not find FStorageInfoFeatureApi" } + return@launch + } + fStorageInfoApi.invalidate(scope = scope) + combine( - serviceApi.connectionInformationApi - .getConnectionStateFlow(), - flipperStorageInformationApi - .getStorageInformationFlow() + fDeviceOrchestrator.getState(), + fStorageInfoApi.getStorageInformationFlow() ) { connectionState, flipperStorageInformation -> connectionState to flipperStorageInformation }.collectLatest { (connectionState, flipperStorageInformation) -> @@ -106,16 +108,16 @@ class FapManifestsLoader @AssistedInject constructor( @Suppress("LongMethod") private suspend fun loadInternal( - connectionState: ConnectionState, + connectionState: FDeviceConnectStatus, storageInformation: FlipperStorageInformation ) { val isUseDevCatalog = dataStoreSettings.data.first().use_dev_catalog - val serviceApi = flipperServiceProvider.getServiceApi() - if (!connectionState.isReady) { + + if (connectionState !is FDeviceConnectStatus.Connected) { throw FlipperNotConnected() } val externalStorageStatus = storageInformation.externalStorageStatus - as? FlipperInformationStatus.Ready + as? FlipperInformationStatus.Ready if (externalStorageStatus == null || externalStorageStatus.data !is StorageStats.Loaded) { throw NoSdCardException() } @@ -144,10 +146,8 @@ class FapManifestsLoader @AssistedInject constructor( } info { "Parsed ${fapItemsList.size} manifests from cache" } cacheResult.toLoadNames.mapNotNull { name -> - loadManifestFile( - requestApi = serviceApi.requestApi, - filePath = File(FAP_MANIFESTS_FOLDER_ON_FLIPPER, name).absolutePath - )?.let { parser.parse(it, name) } + loadManifestFile(filePath = File(FAP_MANIFESTS_FOLDER_ON_FLIPPER, name).absolutePath) + ?.let { byteArray -> parser.parse(byteArray, name) } }.filter { fapExistChecker.checkExist(it.path) } .filter { it.isDevCatalog == isUseDevCatalog } .forEach { content -> @@ -172,24 +172,18 @@ class FapManifestsLoader @AssistedInject constructor( } private suspend fun loadManifestFile( - requestApi: FlipperRequestApi, filePath: String - ): ByteArray? { - val responseBytes = requestApi.request( - main { - storageReadRequest = readRequest { - path = filePath - } - }.wrapToRequest(FlipperRequestPriority.BACKGROUND) - ).toList().map { response -> - if (response.hasStorageReadResponse()) { - response.storageReadResponse.file.data.toByteArray() - } else { - return null - } - }.flatten() - - return responseBytes + ): ByteArray? = coroutineScope { + fFeatureProvider + .getSync() + ?.downloadApi() + ?.source( + pathOnFlipper = filePath, + priority = StorageRequestPriority.BACKGROUND, + scope = this + ) + ?.buffer() + ?.readByteArray() } @AssistedFactory From 0d533faeb775653e24ce06f1cd55c6df4f6528f7 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Tue, 17 Dec 2024 15:13:17 +0300 Subject: [PATCH 3/7] convert queue module into new api --- .../installation/queue/impl/build.gradle.kts | 10 ++-- .../impl/executor/actions/FapActionUpload.kt | 47 +++++++------------ 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/components/faphub/installation/queue/impl/build.gradle.kts b/components/faphub/installation/queue/impl/build.gradle.kts index 7532025809..55e2ee446f 100644 --- a/components/faphub/installation/queue/impl/build.gradle.kts +++ b/components/faphub/installation/queue/impl/build.gradle.kts @@ -24,9 +24,13 @@ dependencies { implementation(projects.components.analytics.metric.api) - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.pbutils) - implementation(projects.components.bridge.service.api) + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.feature.storage.api) + +// implementation(projects.components.bridge.api) +// implementation(projects.components.bridge.pbutils) +// implementation(projects.components.bridge.service.api) implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) diff --git a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt index 3755d5b612..2871d362c8 100644 --- a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt +++ b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt @@ -1,23 +1,23 @@ package com.flipperdevices.faphub.installation.queue.impl.executor.actions -import com.flipperdevices.bridge.api.model.FlipperRequest -import com.flipperdevices.bridge.protobuf.streamToCommandFlow -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.getSync +import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import com.flipperdevices.core.log.info import com.flipperdevices.core.progress.ProgressListener import com.flipperdevices.core.progress.ProgressWrapperTracker +import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.faphub.utils.FapHubTmpFolderProvider -import com.flipperdevices.protobuf.Flipper -import com.flipperdevices.protobuf.storage.file -import com.flipperdevices.protobuf.storage.writeRequest import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking +import okio.source import java.io.File import javax.inject.Inject class FapActionUpload @Inject constructor( - private val serviceProvider: FlipperServiceProvider, + private val fFeatureProvider: FFeatureProvider, private val tmpFolderProvider: FapHubTmpFolderProvider ) : LogTagProvider { override val TAG = "FapActionUpload" @@ -27,38 +27,25 @@ class FapActionUpload @Inject constructor( progressListener: ProgressListener ): String { info { "Start upload ${fapFile.absolutePath}" } - val requestApi = serviceProvider.getServiceApi().requestApi + val fStorageFeatureApi = fFeatureProvider + .getSync() + ?: error("Could not get FStorageFeatureApi") val fapPath = File( tmpFolderProvider.provideTmpFolder(), "tmp.fap" ).absolutePath val progressWrapper = ProgressWrapperTracker(progressListener) - val totalLength = fapFile.length() - var uploadedBytes = 0L - val response = fapFile.inputStream().use { inputStream -> - val requestFlow = streamToCommandFlow(inputStream, totalLength) { chunkData -> - storageWriteRequest = writeRequest { - path = fapPath - file = file { data = chunkData } - } - }.map { - FlipperRequest( - data = it, - onSendCallback = { - uploadedBytes += it.storageWriteRequest.file.data.size() - runBlocking { - progressWrapper.onProgress(uploadedBytes, totalLength) - } + runCatching { + fapFile.inputStream().use { inputStream -> + inputStream.source().copyWithProgress( + sink = fStorageFeatureApi.uploadApi().sink(fapPath), + progressListener = { current, max -> + progressWrapper.onProgress(current, max) } ) } + }.onFailure { error(it) { "Failed upload tmp manifest" } }.getOrThrow() - requestApi.request(requestFlow) - } - - if (response.commandStatus != Flipper.CommandStatus.OK) { - error("Failed upload tmp manifest, command status is ${response.commandStatus}") - } return fapPath } } From 234b6a1a680a6d769473e23a6f6a899f8f522d80 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Tue, 17 Dec 2024 16:14:34 +0300 Subject: [PATCH 4/7] convert faphub module into new api --- .../device/fzero/impl/build.gradle.kts | 1 + .../utils/FZeroFeatureClassToEnumMapper.kt | 3 + .../feature/appstart/api/build.gradle.kts | 19 ++++ .../appstart/api/FAppStartFeatureApi.kt | 7 ++ .../feature/appstart/impl/build.gradle.kts | 28 +++++ .../impl/api/FAppStartFeatureApiImpl.kt | 34 ++++++ .../impl/api/FAppStartFeatureFactoryImpl.kt | 46 ++++++++ .../feature/common/api/FDeviceFeature.kt | 3 +- .../installation/button/impl/build.gradle.kts | 14 ++- .../button/impl/helper/OpenFapHelper.kt | 102 ++++++++---------- .../manifest/impl/utils/FapExistChecker.kt | 2 +- .../impl/utils/FapManifestAtomicMover.kt | 2 - .../impl/utils/FapManifestCacheLoader.kt | 1 - .../manifest/impl/utils/FapManifestsLoader.kt | 4 +- .../impl/executor/actions/FapActionUpload.kt | 2 - instances/android/app/build.gradle.kts | 2 + settings.gradle.kts | 2 + 17 files changed, 204 insertions(+), 68 deletions(-) create mode 100644 components/bridge/connection/feature/appstart/api/build.gradle.kts create mode 100644 components/bridge/connection/feature/appstart/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/api/FAppStartFeatureApi.kt create mode 100644 components/bridge/connection/feature/appstart/impl/build.gradle.kts create mode 100644 components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt create mode 100644 components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureFactoryImpl.kt diff --git a/components/bridge/connection/device/fzero/impl/build.gradle.kts b/components/bridge/connection/device/fzero/impl/build.gradle.kts index 662db55269..adb845a707 100644 --- a/components/bridge/connection/device/fzero/impl/build.gradle.kts +++ b/components/bridge/connection/device/fzero/impl/build.gradle.kts @@ -28,6 +28,7 @@ commonDependencies { implementation(projects.components.bridge.connection.feature.getinfo.api) implementation(projects.components.bridge.connection.feature.alarm.api) implementation(projects.components.bridge.connection.feature.deviceColor.api) + implementation(projects.components.bridge.connection.feature.appstart.api) implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) diff --git a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt index ca9b4bb7bf..29f4e69394 100644 --- a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt +++ b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt @@ -1,6 +1,7 @@ package com.flipperdevices.bridge.connection.device.fzero.impl.utils import com.flipperdevices.bridge.connection.feature.alarm.api.FAlarmFeatureApi +import com.flipperdevices.bridge.connection.feature.appstart.api.FAppStartFeatureApi import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi import com.flipperdevices.bridge.connection.feature.devicecolor.api.FDeviceColorFeatureApi @@ -23,6 +24,7 @@ object FZeroFeatureClassToEnumMapper { private val classToEnumMap: ImmutableMap, FDeviceFeature> = FDeviceFeature.entries.associateBy { featureEnumToClass(it) }.toPersistentMap() + @Suppress("CyclomaticComplexMethod") private fun featureEnumToClass(feature: FDeviceFeature): KClass { return when (feature) { FDeviceFeature.RPC -> FRpcFeatureApi::class @@ -38,6 +40,7 @@ object FZeroFeatureClassToEnumMapper { FDeviceFeature.DEVICE_COLOR -> FDeviceColorFeatureApi::class FDeviceFeature.GATT_INFO -> FGattInfoFeatureApi::class FDeviceFeature.SDK_VERSION -> FSdkVersionFeatureApi::class + FDeviceFeature.APP_START -> FAppStartFeatureApi::class } } diff --git a/components/bridge/connection/feature/appstart/api/build.gradle.kts b/components/bridge/connection/feature/appstart/api/build.gradle.kts new file mode 100644 index 0000000000..09a9285b9c --- /dev/null +++ b/components/bridge/connection/feature/appstart/api/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.appstart.api" + +commonDependencies { + implementation(projects.components.core.data) + implementation(projects.components.core.ktx) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + + implementation(libs.kotlin.immutable.collections) + implementation(libs.kotlin.coroutines) + implementation(libs.okio) +} diff --git a/components/bridge/connection/feature/appstart/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/api/FAppStartFeatureApi.kt b/components/bridge/connection/feature/appstart/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/api/FAppStartFeatureApi.kt new file mode 100644 index 0000000000..7e98007f6a --- /dev/null +++ b/components/bridge/connection/feature/appstart/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/api/FAppStartFeatureApi.kt @@ -0,0 +1,7 @@ +package com.flipperdevices.bridge.connection.feature.appstart.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi + +interface FAppStartFeatureApi : FDeviceFeatureApi { + suspend fun startApp(path: okio.Path): Result +} diff --git a/components/bridge/connection/feature/appstart/impl/build.gradle.kts b/components/bridge/connection/feature/appstart/impl/build.gradle.kts new file mode 100644 index 0000000000..0c82ae7696 --- /dev/null +++ b/components/bridge/connection/feature/appstart/impl/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") + id("flipper.anvil-multiplatform") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.appstart.impl" + +commonDependencies { + implementation(projects.components.bridge.connection.feature.appstart.api) + + implementation(projects.components.core.di) + implementation(projects.components.core.log) + implementation(projects.components.core.ktx) + implementation(projects.components.core.data) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.rpc.api) + implementation(projects.components.bridge.connection.feature.rpc.model) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + implementation(projects.components.bridge.connection.feature.protocolversion.api) + + implementation(projects.components.bridge.connection.pbutils) + + implementation(libs.kotlin.coroutines) + implementation(libs.okio) +} diff --git a/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt new file mode 100644 index 0000000000..867e083af2 --- /dev/null +++ b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt @@ -0,0 +1,34 @@ +package com.flipperdevices.bridge.connection.feature.appstart.impl.api + +import com.flipperdevices.bridge.connection.feature.appstart.api.FAppStartFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.model.wrapToRequest +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.protobuf.Main +import com.flipperdevices.protobuf.app.StartRequest +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import okio.Path + +class FAppStartFeatureApiImpl @AssistedInject constructor( + @Assisted private val rpcFeatureApi: FRpcFeatureApi, +) : FAppStartFeatureApi, + LogTagProvider { + override val TAG = "FAlarmFeatureApi" + + override suspend fun startApp(path: Path): Result { + return rpcFeatureApi.requestOnce( + Main( + app_start_request = StartRequest(path.toString()) + ).wrapToRequest() + ).map { } + } + + @AssistedFactory + fun interface InternalFactory { + operator fun invoke( + rpcFeatureApi: FRpcFeatureApi, + ): FAppStartFeatureApiImpl + } +} diff --git a/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureFactoryImpl.kt b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureFactoryImpl.kt new file mode 100644 index 0000000000..bc34f7466c --- /dev/null +++ b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureFactoryImpl.kt @@ -0,0 +1,46 @@ +package com.flipperdevices.bridge.connection.feature.appstart.impl.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature +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.protocolversion.api.FVersionFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi +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 + +// TODO move to consts +val API_SUPPORTED_LOAD_FAP = SemVer( + majorVersion = 0, + minorVersion = 18 +) + +@FDeviceFeatureQualifier(FDeviceFeature.APP_START) +@ContributesMultibinding(AppGraph::class, FDeviceFeatureApi.Factory::class) +class FAppStartFeatureFactoryImpl @Inject constructor( + private val factory: FAppStartFeatureApiImpl.InternalFactory +) : FDeviceFeatureApi.Factory { + override suspend fun invoke( + unsafeFeatureDeviceApi: FUnsafeDeviceFeatureApi, + scope: CoroutineScope, + connectedDevice: FConnectedDeviceApi + ): FDeviceFeatureApi? { + val versionApi = unsafeFeatureDeviceApi.getUnsafe(FVersionFeatureApi::class) ?: return null + info { "Start request supported state for api level $API_SUPPORTED_LOAD_FAP" } + val isSupported = versionApi.isSupported(API_SUPPORTED_LOAD_FAP) + if (!isSupported) { + error { "Failed init FDeviceColorFeatureApi, because isSupported=false" } + return null + } + val rpcApi = unsafeFeatureDeviceApi.getUnsafe(FRpcFeatureApi::class) ?: return null + return factory( + rpcFeatureApi = rpcApi, + ) + } +} diff --git a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt index 7509891994..848307b0fe 100644 --- a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt +++ b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt @@ -15,7 +15,8 @@ enum class FDeviceFeature { ALARM, DEVICE_COLOR, GATT_INFO, - SDK_VERSION + SDK_VERSION, + APP_START } @Retention(AnnotationRetention.RUNTIME) diff --git a/components/faphub/installation/button/impl/build.gradle.kts b/components/faphub/installation/button/impl/build.gradle.kts index 4e3df2a772..0959685542 100644 --- a/components/faphub/installation/button/impl/build.gradle.kts +++ b/components/faphub/installation/button/impl/build.gradle.kts @@ -23,9 +23,16 @@ dependencies { implementation(projects.components.rootscreen.api) implementation(projects.components.deeplink.api) - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.service.api) - implementation(projects.components.bridge.pbutils) +// implementation(projects.components.bridge.api) +// implementation(projects.components.bridge.service.api) +// implementation(projects.components.bridge.pbutils) + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.feature.storage.api) + implementation(projects.components.bridge.connection.feature.protocolversion.api) + implementation(projects.components.bridge.connection.feature.appstart.api) + implementation(projects.components.bridge.connection.feature.rpc.api) implementation(projects.components.faphub.installation.stateprovider.api) implementation(projects.components.faphub.installation.manifest.api) @@ -43,4 +50,5 @@ dependencies { implementation(libs.kotlin.coroutines) implementation(libs.lifecycle.viewmodel.ktx) + implementation(libs.okio) } diff --git a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt index 25bd79b7c5..7e9dd30545 100644 --- a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt +++ b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt @@ -1,10 +1,11 @@ package com.flipperdevices.faphub.installation.button.impl.helper -import com.flipperdevices.bridge.api.model.FlipperRequestPriority -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.api.utils.Constants -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider -import com.flipperdevices.core.data.SemVer +import com.flipperdevices.bridge.connection.feature.appstart.api.FAppStartFeatureApi +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.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.rpc.api.exception.FRpcAppSystemLockedException import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.log.LogTagProvider @@ -13,18 +14,13 @@ import com.flipperdevices.faphub.dao.api.model.FapBuildState import com.flipperdevices.faphub.installation.button.api.FapButtonConfig import com.flipperdevices.faphub.installation.button.impl.model.OpenFapResult import com.flipperdevices.faphub.installation.button.impl.model.OpenFapState -import com.flipperdevices.protobuf.Flipper -import com.flipperdevices.protobuf.app.startRequest -import com.flipperdevices.protobuf.main import com.squareup.anvil.annotations.ContributesBinding import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.launch +import okio.Path.Companion.toPath import javax.inject.Inject import javax.inject.Singleton @@ -39,43 +35,32 @@ interface OpenFapHelper { @Singleton @ContributesBinding(AppGraph::class, OpenFapHelper::class) class OpenFapHelperImpl @Inject constructor( - private val serviceProvider: FlipperServiceProvider + private val fFeatureProvider: FFeatureProvider ) : OpenFapHelper, LogTagProvider { override val TAG: String = "OpenFapHelperImpl" private val currentOpenAppFlow = MutableStateFlow(null) - private val rpcVersionFlow = MutableStateFlow(null) - - private val scope = CoroutineScope(SupervisorJob() + FlipperDispatchers.workStealingDispatcher) override fun getOpenFapState(fapButtonConfig: FapButtonConfig?): Flow { return combine( - currentOpenAppFlow, - rpcVersionFlow, - ) { currentApp, rpcVersion -> - return@combine when { - fapButtonConfig == null -> OpenFapState.NotSupported - rpcVersion == null || rpcVersion < Constants.API_SUPPORTED_LOAD_FAP -> - OpenFapState.NotSupported + flow = fFeatureProvider.get(), + flow2 = currentOpenAppFlow, + transform = { status, currentApp -> + when { + status is FFeatureStatus.Unsupported -> OpenFapState.NotSupported + status is FFeatureStatus.NotFound -> OpenFapState.NotSupported + fapButtonConfig == null -> OpenFapState.NotSupported - fapButtonConfig.version.buildState != FapBuildState.READY -> - OpenFapState.NotSupported + fapButtonConfig.version.buildState != FapBuildState.READY -> { + OpenFapState.NotSupported + } - currentApp != null -> - OpenFapState.InProgress(currentApp) + currentApp != null -> OpenFapState.InProgress(currentApp) - else -> OpenFapState.Ready + else -> OpenFapState.Ready + } } - } - } - - init { - scope.launch(FlipperDispatchers.workStealingDispatcher) { - val serviceApi = serviceProvider.getServiceApi() - serviceApi.flipperVersionApi.getVersionInformationFlow().collectLatest { - rpcVersionFlow.emit(it) - } - } + ) } override suspend fun loadFap( @@ -87,25 +72,32 @@ class OpenFapHelperImpl @Inject constructor( return } - val path = "${Constants.PATH.APPS}${config.categoryAlias}/${config.applicationAlias}.fap" - val serviceApi = serviceProvider.getServiceApi() - - val appLoadResponse = serviceApi.requestApi.request( - flowOf( - main { - appStartRequest = startRequest { - name = path - } - }.wrapToRequest(FlipperRequestPriority.FOREGROUND) - ) - ) - - val result: OpenFapResult = when (appLoadResponse.commandStatus) { - Flipper.CommandStatus.OK -> OpenFapResult.AllGood - Flipper.CommandStatus.ERROR_APP_SYSTEM_LOCKED -> OpenFapResult.FlipperIsBusy - else -> OpenFapResult.Error + val path = APPS_PATH + .resolve(config.categoryAlias) + .resolve(config.applicationAlias.plus(".fap")) + val fAppStartFeatureApi = fFeatureProvider.getSync() + if (fAppStartFeatureApi == null) { + currentOpenAppFlow.emit(null) + onResult(OpenFapResult.Error) + return } + currentOpenAppFlow.emit(null) - onResult(result) + fAppStartFeatureApi.startApp(path) + .onFailure { + val result = when (it) { + is FRpcAppSystemLockedException -> OpenFapResult.FlipperIsBusy + else -> OpenFapResult.Error + } + onResult(result) + } + .onSuccess { + onResult(OpenFapResult.AllGood) + } + } + + companion object { + // TODO move somewhere else + private val APPS_PATH = "/ext/apps/".toPath() } } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt index 55079d4715..6bc3995e9e 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt @@ -28,7 +28,7 @@ class FapExistChecker @Inject constructor( ?.ls(folder) ?.getOrNull() .orEmpty() - .map { item-> Path(folder).resolve(item.fileName).toString() } + .map { item -> Path(folder).resolve(item.fileName).toString() } .also { paths -> cacheFolderToPaths[folder] = paths } return@withLockResult fileList.contains(path) diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt index d5b37292bb..b77e78b640 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt @@ -10,7 +10,6 @@ import com.flipperdevices.core.log.error import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext -import okio.Path import okio.Path.Companion.toPath import java.io.File import javax.inject.Inject @@ -38,7 +37,6 @@ class FapManifestAtomicMover @Inject constructor( val deleteTargets = fromToPair.map { pair -> pair.second } - withContext(NonCancellable) { if (fSemVer == null || fSemVer < UNIX_MV_SUPPORTED_VERSION_API) { deleteTargets.map { target -> diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt index b22a12304b..9992cc5cf5 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestCacheLoader.kt @@ -13,7 +13,6 @@ import com.flipperdevices.core.log.info import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext -import okio.Path import java.io.File import javax.inject.Inject import javax.inject.Singleton diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt index 59856242ad..79300a98f9 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestsLoader.kt @@ -11,7 +11,6 @@ import com.flipperdevices.bridge.connection.feature.storageinfo.model.FlipperSto import com.flipperdevices.bridge.connection.feature.storageinfo.model.StorageStats import com.flipperdevices.bridge.connection.orchestrator.api.FDeviceOrchestrator import com.flipperdevices.bridge.connection.orchestrator.api.model.FDeviceConnectStatus -import com.flipperdevices.core.ktx.jre.flatten import com.flipperdevices.core.ktx.jre.launchWithLock import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.error @@ -37,7 +36,6 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import okio.buffer @@ -117,7 +115,7 @@ class FapManifestsLoader @AssistedInject constructor( throw FlipperNotConnected() } val externalStorageStatus = storageInformation.externalStorageStatus - as? FlipperInformationStatus.Ready + as? FlipperInformationStatus.Ready if (externalStorageStatus == null || externalStorageStatus.data !is StorageStats.Loaded) { throw NoSdCardException() } diff --git a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt index 2871d362c8..d066ad8c95 100644 --- a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt +++ b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt @@ -10,8 +10,6 @@ import com.flipperdevices.core.progress.ProgressListener import com.flipperdevices.core.progress.ProgressWrapperTracker import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.faphub.utils.FapHubTmpFolderProvider -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.runBlocking import okio.source import java.io.File import javax.inject.Inject diff --git a/instances/android/app/build.gradle.kts b/instances/android/app/build.gradle.kts index 82f582ccbd..59abc00495 100644 --- a/instances/android/app/build.gradle.kts +++ b/instances/android/app/build.gradle.kts @@ -188,6 +188,8 @@ dependencies { implementation(projects.components.bridge.connection.feature.alarm.impl) implementation(projects.components.bridge.connection.feature.deviceColor.api) implementation(projects.components.bridge.connection.feature.deviceColor.impl) + implementation(projects.components.bridge.connection.feature.appstart.api) + implementation(projects.components.bridge.connection.feature.appstart.impl) implementation(projects.components.analytics.shake2report.api) if (IS_SENTRY_ENABLED) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 9239ebf125..37fe8ec280 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -91,6 +91,8 @@ include( ":components:bridge:connection:feature:alarm:impl", ":components:bridge:connection:feature:device-color:api", ":components:bridge:connection:feature:device-color:impl", + ":components:bridge:connection:feature:appstart:api", + ":components:bridge:connection:feature:appstart:impl", ":components:filemngr:util", ":components:filemanager:api", From dd2057a4840fc59a54b25cc3f1245d285d2b2cd5 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Wed, 18 Dec 2024 13:16:21 +0300 Subject: [PATCH 5/7] remove more bridge deps --- .../impl/api/FAppStartFeatureApiImpl.kt | 2 ++ .../bridge/service/impl/FlipperService.kt | 1 + .../installation/button/impl/build.gradle.kts | 3 --- .../button/impl/helper/OpenFapHelper.kt | 2 ++ .../manifest/impl/build.gradle.kts | 5 ----- .../impl/utils/FapManifestUploader.kt | 11 +++++++--- .../installation/queue/impl/build.gradle.kts | 4 ---- .../impl/executor/actions/FapActionUpload.kt | 21 ++++++++++++++----- .../stateprovider/impl/build.gradle.kts | 4 ---- .../api/FapInstallationStateManagerImpl.kt | 2 +- .../faphub/installedtab/impl/build.gradle.kts | 2 -- components/faphub/utils/build.gradle.kts | 6 +----- .../faphub/utils/FapHubConstants.kt | 7 +------ .../faphub/utils/FapHubTmpFolderProvider.kt | 15 ------------- 14 files changed, 32 insertions(+), 53 deletions(-) delete mode 100644 components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubTmpFolderProvider.kt diff --git a/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt index 867e083af2..a62adffdf7 100644 --- a/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt +++ b/components/bridge/connection/feature/appstart/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/appstart/impl/api/FAppStartFeatureApiImpl.kt @@ -4,6 +4,7 @@ import com.flipperdevices.bridge.connection.feature.appstart.api.FAppStartFeatur import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi import com.flipperdevices.bridge.connection.feature.rpc.model.wrapToRequest import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.info import com.flipperdevices.protobuf.Main import com.flipperdevices.protobuf.app.StartRequest import dagger.assisted.Assisted @@ -18,6 +19,7 @@ class FAppStartFeatureApiImpl @AssistedInject constructor( override val TAG = "FAlarmFeatureApi" override suspend fun startApp(path: Path): Result { + info { "#startApp path: $path" } return rpcFeatureApi.requestOnce( Main( app_start_request = StartRequest(path.toString()) diff --git a/components/bridge/service/impl/src/main/java/com/flipperdevices/bridge/service/impl/FlipperService.kt b/components/bridge/service/impl/src/main/java/com/flipperdevices/bridge/service/impl/FlipperService.kt index cf85442cc2..998e5218c2 100644 --- a/components/bridge/service/impl/src/main/java/com/flipperdevices/bridge/service/impl/FlipperService.kt +++ b/components/bridge/service/impl/src/main/java/com/flipperdevices/bridge/service/impl/FlipperService.kt @@ -46,6 +46,7 @@ class FlipperService : LifecycleService(), LogTagProvider { override fun onCreate() { super.onCreate() info { "Start flipper service" } + return val component = ComponentHolder .component() diff --git a/components/faphub/installation/button/impl/build.gradle.kts b/components/faphub/installation/button/impl/build.gradle.kts index 0959685542..c02edefbe6 100644 --- a/components/faphub/installation/button/impl/build.gradle.kts +++ b/components/faphub/installation/button/impl/build.gradle.kts @@ -23,9 +23,6 @@ dependencies { implementation(projects.components.rootscreen.api) implementation(projects.components.deeplink.api) -// implementation(projects.components.bridge.api) -// implementation(projects.components.bridge.service.api) -// implementation(projects.components.bridge.pbutils) implementation(projects.components.bridge.connection.feature.common.api) implementation(projects.components.bridge.connection.feature.rpcinfo.api) implementation(projects.components.bridge.connection.feature.provider.api) diff --git a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt index 7e9dd30545..7d8f026105 100644 --- a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt +++ b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt @@ -9,6 +9,7 @@ import com.flipperdevices.bridge.connection.feature.rpc.api.exception.FRpcAppSys import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import com.flipperdevices.core.log.info import com.flipperdevices.faphub.dao.api.model.FapBuildState import com.flipperdevices.faphub.installation.button.api.FapButtonConfig @@ -85,6 +86,7 @@ class OpenFapHelperImpl @Inject constructor( currentOpenAppFlow.emit(null) fAppStartFeatureApi.startApp(path) .onFailure { + error(it) { "#loadFap could not open app" } val result = when (it) { is FRpcAppSystemLockedException -> OpenFapResult.FlipperIsBusy else -> OpenFapResult.Error diff --git a/components/faphub/installation/manifest/impl/build.gradle.kts b/components/faphub/installation/manifest/impl/build.gradle.kts index 8cb08ee260..277b0c8e03 100644 --- a/components/faphub/installation/manifest/impl/build.gradle.kts +++ b/components/faphub/installation/manifest/impl/build.gradle.kts @@ -29,12 +29,7 @@ dependencies { implementation(projects.components.bridge.connection.feature.storageinfo.api) implementation(projects.components.bridge.connection.orchestrator.api) -// implementation(projects.components.bridge.api) implementation(projects.components.bridge.dao.api) -// implementation(projects.components.bridge.rpc.api) -// implementation(projects.components.bridge.rpcinfo.api) -// implementation(projects.components.bridge.service.api) -// implementation(projects.components.bridge.pbutils) implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt index 3e11769532..cf2e3b7119 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt @@ -10,7 +10,7 @@ import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.faphub.installation.manifest.impl.utils.FapManifestConstants.FAP_MANIFESTS_FOLDER_ON_FLIPPER import com.flipperdevices.faphub.installation.manifest.impl.utils.FapManifestConstants.FAP_MANIFEST_EXTENSION import com.flipperdevices.faphub.installation.manifest.model.FapManifestItem -import com.flipperdevices.faphub.utils.FapHubTmpFolderProvider +import com.flipperdevices.faphub.utils.FapHubConstants import okio.buffer import okio.source import java.io.File @@ -20,7 +20,6 @@ class FapManifestUploader @Inject constructor( private val parser: FapManifestParser, private val fFeatureProvider: FFeatureProvider, private val atomicMover: FapManifestAtomicMover, - private val tmpFolderProvider: FapHubTmpFolderProvider ) : LogTagProvider { override val TAG = "FapManifestUploader" @@ -41,8 +40,14 @@ class FapManifestUploader @Inject constructor( private suspend fun saveToTmp(fapManifestItem: FapManifestItem): String { info { "Start save tmp manifest for ${fapManifestItem.applicationAlias}" } + val uploadApi = fFeatureProvider.getSync()?.uploadApi() + if (uploadApi == null) { + error { "#uploadTmpManifest could not find uploadApi" } + return FapHubConstants.FLIPPER_TMP_FOLDER_PATH + } + uploadApi.mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) val tmpFapPath = File( - tmpFolderProvider.provideTmpFolder(), + FapHubConstants.FLIPPER_TMP_FOLDER_PATH, "tmp.fim" ).path uploadTmpManifest(fapManifestItem, tmpFapPath) diff --git a/components/faphub/installation/queue/impl/build.gradle.kts b/components/faphub/installation/queue/impl/build.gradle.kts index 55e2ee446f..71977fb26c 100644 --- a/components/faphub/installation/queue/impl/build.gradle.kts +++ b/components/faphub/installation/queue/impl/build.gradle.kts @@ -28,10 +28,6 @@ dependencies { implementation(projects.components.bridge.connection.feature.provider.api) implementation(projects.components.bridge.connection.feature.storage.api) -// implementation(projects.components.bridge.api) -// implementation(projects.components.bridge.pbutils) -// implementation(projects.components.bridge.service.api) - implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) implementation(libs.ktor.client) diff --git a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt index d066ad8c95..dcf61d8f9f 100644 --- a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt +++ b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt @@ -9,14 +9,13 @@ import com.flipperdevices.core.log.info import com.flipperdevices.core.progress.ProgressListener import com.flipperdevices.core.progress.ProgressWrapperTracker import com.flipperdevices.core.progress.copyWithProgress -import com.flipperdevices.faphub.utils.FapHubTmpFolderProvider +import com.flipperdevices.faphub.utils.FapHubConstants import okio.source import java.io.File import javax.inject.Inject class FapActionUpload @Inject constructor( private val fFeatureProvider: FFeatureProvider, - private val tmpFolderProvider: FapHubTmpFolderProvider ) : LogTagProvider { override val TAG = "FapActionUpload" @@ -24,24 +23,36 @@ class FapActionUpload @Inject constructor( fapFile: File, progressListener: ProgressListener ): String { - info { "Start upload ${fapFile.absolutePath}" } + info { "#upload Start upload ${fapFile.absolutePath}" } val fStorageFeatureApi = fFeatureProvider .getSync() - ?: error("Could not get FStorageFeatureApi") + ?: run { + error { "#upload could not get FStorageFeatureApi" } + error("Could not get FStorageFeatureApi") + } + info { "#upload got upload feature!" } + fStorageFeatureApi.uploadApi().mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) val fapPath = File( - tmpFolderProvider.provideTmpFolder(), + FapHubConstants.FLIPPER_TMP_FOLDER_PATH, "tmp.fap" ).absolutePath + info { "#upload File is: $fapPath" } val progressWrapper = ProgressWrapperTracker(progressListener) runCatching { + info { "#upload fapFile.inputStream()" } fapFile.inputStream().use { inputStream -> + info { "#upload inputStream.source()" } inputStream.source().copyWithProgress( sink = fStorageFeatureApi.uploadApi().sink(fapPath), progressListener = { current, max -> + info { "#upload onProgress: $current $max" } progressWrapper.onProgress(current, max) + info { "#upload onProgress invoked" } } ) + info { "#upload inputStream.source() finished!" } } + info { "#upload fapFile.inputStream() finished!" } }.onFailure { error(it) { "Failed upload tmp manifest" } }.getOrThrow() return fapPath diff --git a/components/faphub/installation/stateprovider/impl/build.gradle.kts b/components/faphub/installation/stateprovider/impl/build.gradle.kts index 120019977e..5264e05c30 100644 --- a/components/faphub/installation/stateprovider/impl/build.gradle.kts +++ b/components/faphub/installation/stateprovider/impl/build.gradle.kts @@ -13,15 +13,11 @@ dependencies { implementation(projects.components.core.ktx) implementation(projects.components.core.data) - implementation(projects.components.bridge.api) - implementation(projects.components.faphub.dao.api) implementation(projects.components.faphub.installation.manifest.api) implementation(projects.components.faphub.installation.queue.api) implementation(projects.components.faphub.target.api) - implementation(projects.components.bridge.rpc.api) - implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) diff --git a/components/faphub/installation/stateprovider/impl/src/main/java/com/flipperdevices/faphub/installation/stateprovider/impl/api/FapInstallationStateManagerImpl.kt b/components/faphub/installation/stateprovider/impl/src/main/java/com/flipperdevices/faphub/installation/stateprovider/impl/api/FapInstallationStateManagerImpl.kt index c1795ddef9..81c4136e72 100644 --- a/components/faphub/installation/stateprovider/impl/src/main/java/com/flipperdevices/faphub/installation/stateprovider/impl/api/FapInstallationStateManagerImpl.kt +++ b/components/faphub/installation/stateprovider/impl/src/main/java/com/flipperdevices/faphub/installation/stateprovider/impl/api/FapInstallationStateManagerImpl.kt @@ -1,11 +1,11 @@ package com.flipperdevices.faphub.installation.stateprovider.impl.api -import com.flipperdevices.bridge.rpc.api.model.exceptions.NoSdCardException import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.faphub.dao.api.model.FapBuildState import com.flipperdevices.faphub.dao.api.model.FapItemVersion import com.flipperdevices.faphub.installation.manifest.api.FapManifestApi +import com.flipperdevices.faphub.installation.manifest.error.NoSdCardException import com.flipperdevices.faphub.installation.manifest.model.FapManifestState import com.flipperdevices.faphub.installation.queue.api.FapInstallationQueueApi import com.flipperdevices.faphub.installation.queue.api.model.FapActionRequest diff --git a/components/faphub/installedtab/impl/build.gradle.kts b/components/faphub/installedtab/impl/build.gradle.kts index 479f1d916f..57c06658f3 100644 --- a/components/faphub/installedtab/impl/build.gradle.kts +++ b/components/faphub/installedtab/impl/build.gradle.kts @@ -29,8 +29,6 @@ dependencies { implementation(projects.components.inappnotification.api) - implementation(projects.components.bridge.rpc.api) - // Compose implementation(libs.compose.ui) implementation(libs.compose.tooling) diff --git a/components/faphub/utils/build.gradle.kts b/components/faphub/utils/build.gradle.kts index d714b3dd6a..3e006977ec 100644 --- a/components/faphub/utils/build.gradle.kts +++ b/components/faphub/utils/build.gradle.kts @@ -6,11 +6,7 @@ android.namespace = "com.flipperdevices.faphub.utils" dependencies { implementation(projects.components.core.data) - - implementation(projects.components.bridge.api) - implementation(projects.components.bridge.pbutils) - implementation(projects.components.bridge.rpc.api) - + implementation(libs.kotlin.coroutines) implementation(libs.dagger) diff --git a/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubConstants.kt b/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubConstants.kt index 28f6bd3404..7a54315754 100644 --- a/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubConstants.kt +++ b/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubConstants.kt @@ -1,11 +1,6 @@ package com.flipperdevices.faphub.utils -import com.flipperdevices.core.data.SemVer - object FapHubConstants { const val FLIPPER_APPS_FOLDER = "/ext/apps" - val RPC_SUPPORTED_VERSION = SemVer( - majorVersion = 0, - minorVersion = 16 - ) + const val FLIPPER_TMP_FOLDER_PATH = "/ext/.tmp/android" } diff --git a/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubTmpFolderProvider.kt b/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubTmpFolderProvider.kt deleted file mode 100644 index 1691c9f297..0000000000 --- a/components/faphub/utils/src/main/java/com/flipperdevices/faphub/utils/FapHubTmpFolderProvider.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.flipperdevices.faphub.utils - -import com.flipperdevices.bridge.rpc.api.FlipperStorageApi -import javax.inject.Inject - -private const val FLIPPER_TMP_FOLDER_PATH = "/ext/.tmp/android" - -class FapHubTmpFolderProvider @Inject constructor( - private val flipperStorageApi: FlipperStorageApi -) { - suspend fun provideTmpFolder(): String { - flipperStorageApi.mkdirs(FLIPPER_TMP_FOLDER_PATH) - return FLIPPER_TMP_FOLDER_PATH - } -} From 67b768b0d2dcf41021e4186dd3315b59c2034929 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Wed, 18 Dec 2024 13:22:13 +0300 Subject: [PATCH 6/7] fix upload progress --- .../queue/impl/executor/actions/FapActionUpload.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt index dcf61d8f9f..ba4cee7355 100644 --- a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt +++ b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt @@ -10,6 +10,7 @@ import com.flipperdevices.core.progress.ProgressListener import com.flipperdevices.core.progress.ProgressWrapperTracker import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.faphub.utils.FapHubConstants +import kotlinx.coroutines.runBlocking import okio.source import java.io.File import javax.inject.Inject @@ -30,29 +31,22 @@ class FapActionUpload @Inject constructor( error { "#upload could not get FStorageFeatureApi" } error("Could not get FStorageFeatureApi") } - info { "#upload got upload feature!" } fStorageFeatureApi.uploadApi().mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) val fapPath = File( FapHubConstants.FLIPPER_TMP_FOLDER_PATH, "tmp.fap" ).absolutePath - info { "#upload File is: $fapPath" } val progressWrapper = ProgressWrapperTracker(progressListener) runCatching { - info { "#upload fapFile.inputStream()" } fapFile.inputStream().use { inputStream -> - info { "#upload inputStream.source()" } inputStream.source().copyWithProgress( sink = fStorageFeatureApi.uploadApi().sink(fapPath), + sourceLength = { fapFile.length() }, progressListener = { current, max -> - info { "#upload onProgress: $current $max" } - progressWrapper.onProgress(current, max) - info { "#upload onProgress invoked" } + runBlocking { progressWrapper.onProgress(current, max) } } ) - info { "#upload inputStream.source() finished!" } } - info { "#upload fapFile.inputStream() finished!" } }.onFailure { error(it) { "Failed upload tmp manifest" } }.getOrThrow() return fapPath From c1f71d17c0cc9e43225481f4668977d4a2cf1c7f Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Wed, 18 Dec 2024 17:35:28 +0300 Subject: [PATCH 7/7] fix fap items upload --- .../serialization/HardwareColorSerializer.kt | 2 +- .../impl/api/FDeviceColorFeatureApiImpl.kt | 8 +++-- .../button/impl/helper/OpenFapHelper.kt | 3 -- .../manifest/impl/utils/FapExistChecker.kt | 12 ++++--- .../impl/utils/FapManifestAtomicMover.kt | 32 +++++++++++-------- .../impl/utils/FapManifestUploader.kt | 1 + .../impl/executor/actions/FapActionUpload.kt | 23 +++++++------ .../impl/api/FlipperTargetProviderApiImpl.kt | 2 +- components/faphub/utils/build.gradle.kts | 2 +- .../impl/viewmodel/FlipperColorViewModel.kt | 2 -- 10 files changed, 50 insertions(+), 37 deletions(-) diff --git a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt index 2820aff094..383d45dcd0 100644 --- a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt +++ b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt @@ -22,4 +22,4 @@ internal object HardwareColorSerializer : KSerializer { override fun serialize(encoder: Encoder, value: HardwareColor) { encoder.encodeInt(value.value) } -} \ No newline at end of file +} diff --git a/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt index 6dff7c77b4..457248df41 100644 --- a/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt +++ b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt @@ -31,9 +31,11 @@ class FDeviceColorFeatureApiImpl @AssistedInject constructor( } val intHardwareColor = fGetInfoFeatureApi.get(FGetInfoApiProperty.DeviceInfo.HARDWARE_COLOR) - .onFailure { error( - it - ) { "#updateAndGetColorFlow could not fetch ${FGetInfoApiProperty.DeviceInfo.HARDWARE_COLOR}" } } + .onFailure { + error( + it + ) { "#updateAndGetColorFlow could not fetch ${FGetInfoApiProperty.DeviceInfo.HARDWARE_COLOR}" } + } .map { it.toIntOrNull() } .getOrNull() diff --git a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt index 7d8f026105..1934cc6953 100644 --- a/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt +++ b/components/faphub/installation/button/impl/src/main/java/com/flipperdevices/faphub/installation/button/impl/helper/OpenFapHelper.kt @@ -7,7 +7,6 @@ import com.flipperdevices.bridge.connection.feature.provider.api.get import com.flipperdevices.bridge.connection.feature.provider.api.getSync import com.flipperdevices.bridge.connection.feature.rpc.api.exception.FRpcAppSystemLockedException import com.flipperdevices.core.di.AppGraph -import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.error import com.flipperdevices.core.log.info @@ -16,8 +15,6 @@ import com.flipperdevices.faphub.installation.button.api.FapButtonConfig import com.flipperdevices.faphub.installation.button.impl.model.OpenFapResult import com.flipperdevices.faphub.installation.button.impl.model.OpenFapState import com.squareup.anvil.annotations.ContributesBinding -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt index 6bc3995e9e..ade38def01 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapExistChecker.kt @@ -6,6 +6,7 @@ import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureA import com.flipperdevices.core.ktx.jre.withLock import com.flipperdevices.core.ktx.jre.withLockResult import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import kotlinx.coroutines.sync.Mutex import javax.inject.Inject import kotlin.io.path.Path @@ -21,16 +22,19 @@ class FapExistChecker @Inject constructor( suspend fun checkExist(path: String): Boolean = withLockResult(mutex, "check") { val folder = Path(path).parent?.pathString ?: "/" + val fStorageFeatureApi = fFeatureProvider.getSync() + if (fStorageFeatureApi == null) { + error { "#checkExists($path) could not get FStorageFeatureApi" } + } - val fileList = cacheFolderToPaths[folder] - ?: fFeatureProvider.getSync() + val fileList = cacheFolderToPaths.getOrPut(folder) { + fStorageFeatureApi ?.listingApi() ?.ls(folder) ?.getOrNull() .orEmpty() .map { item -> Path(folder).resolve(item.fileName).toString() } - .also { paths -> cacheFolderToPaths[folder] = paths } - + } return@withLockResult fileList.contains(path) } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt index b77e78b640..6891ece5c6 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestAtomicMover.kt @@ -8,6 +8,8 @@ import com.flipperdevices.core.data.SemVer import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.error import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import okio.Path.Companion.toPath @@ -23,25 +25,31 @@ class FapManifestAtomicMover @Inject constructor( suspend fun atomicMove( vararg fromToPair: Pair ) { - val fSemVer = fFeatureProvider.getSync() - ?.getVersionInformationFlow() - ?.first() - val fStorageFeatureApi = fFeatureProvider.getSync() if (fStorageFeatureApi == null) { error { "#atomicMove could not find FStorageFeatureApi" } return } fromToPair.mapNotNull { (_, to) -> File(to).parent } - .forEach { fullPath -> fStorageFeatureApi.uploadApi().mkdir(fullPath) } - - val deleteTargets = fromToPair.map { pair -> pair.second } + .forEach { fullPath -> + fStorageFeatureApi.uploadApi().mkdir(fullPath) + .onFailure { error(it) { "#atomicMove could not mkdir($fullPath)" } } + } withContext(NonCancellable) { + val fSemVer = fFeatureProvider.getSync() + ?.getVersionInformationFlow() + ?.first() if (fSemVer == null || fSemVer < UNIX_MV_SUPPORTED_VERSION_API) { - deleteTargets.map { target -> - fStorageFeatureApi.deleteApi().delete(target) - } + fromToPair + .map { pair -> pair.second } + .map { target -> + async { + fStorageFeatureApi.deleteApi().delete(target) + .onFailure { error(it) { "#atomicMove could not delete $target" } } + } + } + .awaitAll() } fromToPair.map { (from, to) -> @@ -49,9 +57,7 @@ class FapManifestAtomicMover @Inject constructor( oldPath = from.toPath(), newPath = to.toPath() ) - }.onEach { result -> - result - .onFailure { error(it) { "Failed move path" } } + .onFailure { error(it) { "#atomicMove could not move $from -> $to" } } .getOrThrow() } } diff --git a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt index cf2e3b7119..53bbbc2347 100644 --- a/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt +++ b/components/faphub/installation/manifest/impl/src/main/java/com/flipperdevices/faphub/installation/manifest/impl/utils/FapManifestUploader.kt @@ -46,6 +46,7 @@ class FapManifestUploader @Inject constructor( return FapHubConstants.FLIPPER_TMP_FOLDER_PATH } uploadApi.mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) + .onFailure { error(it) { "#saveToTmp could not mkdir ${FapHubConstants.FLIPPER_TMP_FOLDER_PATH}" } } val tmpFapPath = File( FapHubConstants.FLIPPER_TMP_FOLDER_PATH, "tmp.fim" diff --git a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt index ba4cee7355..d55502c2c1 100644 --- a/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt +++ b/components/faphub/installation/queue/impl/src/main/java/com/flipperdevices/faphub/installation/queue/impl/executor/actions/FapActionUpload.kt @@ -11,6 +11,7 @@ import com.flipperdevices.core.progress.ProgressWrapperTracker import com.flipperdevices.core.progress.copyWithProgress import com.flipperdevices.faphub.utils.FapHubConstants import kotlinx.coroutines.runBlocking +import okio.buffer import okio.source import java.io.File import javax.inject.Inject @@ -31,21 +32,25 @@ class FapActionUpload @Inject constructor( error { "#upload could not get FStorageFeatureApi" } error("Could not get FStorageFeatureApi") } - fStorageFeatureApi.uploadApi().mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) + fStorageFeatureApi.uploadApi() + .mkdir(FapHubConstants.FLIPPER_TMP_FOLDER_PATH) + .onFailure { error(it) { "#upload could not create dir ${FapHubConstants.FLIPPER_TMP_FOLDER_PATH}" } } val fapPath = File( FapHubConstants.FLIPPER_TMP_FOLDER_PATH, "tmp.fap" ).absolutePath val progressWrapper = ProgressWrapperTracker(progressListener) runCatching { - fapFile.inputStream().use { inputStream -> - inputStream.source().copyWithProgress( - sink = fStorageFeatureApi.uploadApi().sink(fapPath), - sourceLength = { fapFile.length() }, - progressListener = { current, max -> - runBlocking { progressWrapper.onProgress(current, max) } - } - ) + fapFile.source().buffer().use { source -> + fStorageFeatureApi.uploadApi().sink(fapPath).use { sink -> + source.copyWithProgress( + sink = sink, + sourceLength = { fapFile.length() }, + progressListener = { current, max -> + runBlocking { progressWrapper.onProgress(current, max) } + } + ) + } } }.onFailure { error(it) { "Failed upload tmp manifest" } }.getOrThrow() diff --git a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt index be6225b2ec..77ccb18a3e 100644 --- a/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt +++ b/components/faphub/target/impl/src/main/java/com/flipperdevices/faphub/target/impl/api/FlipperTargetProviderApiImpl.kt @@ -71,7 +71,7 @@ class FlipperTargetProviderApiImpl @Inject constructor( FFeatureStatus.NotFound, FFeatureStatus.Unsupported -> { - targetFlow.emit(FlipperTarget.NotConnected) + targetFlow.emit(FlipperTarget.Unsupported) return@combine } } diff --git a/components/faphub/utils/build.gradle.kts b/components/faphub/utils/build.gradle.kts index 3e006977ec..ece43b741b 100644 --- a/components/faphub/utils/build.gradle.kts +++ b/components/faphub/utils/build.gradle.kts @@ -6,7 +6,7 @@ android.namespace = "com.flipperdevices.faphub.utils" dependencies { implementation(projects.components.core.data) - + implementation(libs.kotlin.coroutines) implementation(libs.dagger) diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt index 82140a5a0e..c6a9b12505 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt @@ -2,9 +2,7 @@ package com.flipperdevices.info.impl.viewmodel import com.flipperdevices.bridge.connection.config.api.FDevicePersistedStorage import com.flipperdevices.bridge.connection.config.api.model.FDeviceFlipperZeroBleModel -import com.flipperdevices.core.preference.pb.FlipperZeroBle import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor -import com.flipperdevices.core.preference.pb.SavedDevice import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow