Yandex штуки

This commit is contained in:
2026-05-03 22:03:47 +03:00
parent be1ba29f4d
commit ad985679ee
11 changed files with 113 additions and 38 deletions

View File

@@ -0,0 +1,5 @@
package com.github.nullptroma.wallenc.data.network.yandexdisk
import java.io.IOException
class YandexDiskAuthException(message: String? = null) : IOException(message)

View File

@@ -1,10 +1,13 @@
package com.github.nullptroma.wallenc.data.network.yandexdisk.repository
import android.util.Log
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.github.nullptroma.wallenc.data.network.yandexdisk.YandexDiskApi
import com.github.nullptroma.wallenc.data.network.yandexdisk.YandexDiskAuthException
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.CustomPropertiesPatchDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.DiskInfoDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.EmbeddedResourceListDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.LinkDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.OperationStatusDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.ResourceDto
@@ -22,8 +25,6 @@ import retrofit2.Response
import java.io.IOException
import java.io.InputStream
class YandexDiskAuthException(message: String? = null) : IOException(message)
class YandexDiskRepository(
private val api: YandexDiskApi,
private val rawHttp: okhttp3.OkHttpClient,
@@ -36,7 +37,15 @@ class YandexDiskRepository(
suspend fun list(path: String, limit: Int, offset: Int, sort: String? = null): ResourceDto =
withContext(ioDispatcher) {
wrapAuth { api.listResources(path, limit, offset, sort) }
try {
wrapAuth { api.listResources(path, limit, offset, sort) }
} catch (e: HttpException) {
if (e.code() == 404) {
ResourceDto(embedded = EmbeddedResourceListDto(items = emptyList()))
} else {
throw e
}
}
}
suspend fun get(path: String): ResourceDto = withContext(ioDispatcher) {
@@ -47,7 +56,7 @@ class YandexDiskRepository(
val resp = wrapAuth { api.createFolder(path) }
when (resp.code()) {
201 -> Unit
409 -> Unit // уже существует
409 -> Unit
else -> throw failure("createFolder", resp)
}
}
@@ -170,8 +179,17 @@ class YandexDiskRepository(
try {
return block()
} catch (e: HttpException) {
if (e.code() == 401) throw YandexDiskAuthException(e.message())
throw e
when (e.code()) {
401 -> {
Log.w(TAG, "Disk API 401: ${e.message()}")
throw YandexDiskAuthException(e.message())
}
404 -> throw e
else -> {
Log.w(TAG, "Disk API HTTP ${e.code()}: ${e.message()}")
throw e
}
}
}
}
@@ -184,6 +202,7 @@ class YandexDiskRepository(
jackson.readValue(body.string())
companion object {
private const val TAG = "YandexDiskRepo"
private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
private val OCTET_STREAM = "application/octet-stream".toMediaType()
private const val OPERATION_POLL_DELAY_MS = 300L

View File

@@ -86,10 +86,8 @@ abstract class BaseStorage(
private suspend fun updateMetaInfo(meta: IStorageMetaInfo) = withContext(ioDispatcher) {
val writer = accessor.openWriteSystemFile(metaInfoFileName)
try {
writer.use { writer ->
jackson.writeValue(writer, meta)
} finally {
writer.close()
}
_metaInfo.value = meta
}

View File

@@ -1,6 +1,6 @@
package com.github.nullptroma.wallenc.data.storages.yandex
import com.github.nullptroma.wallenc.data.network.yandexdisk.repository.YandexDiskAuthException
import com.github.nullptroma.wallenc.data.network.yandexdisk.YandexDiskAuthException
import com.github.nullptroma.wallenc.data.network.yandexdisk.dto.ResourceDto
import com.github.nullptroma.wallenc.data.network.yandexdisk.repository.YandexDiskRepository
import com.github.nullptroma.wallenc.data.utils.CloseHandledStreamExtension.Companion.onClosed
@@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
import android.util.Log
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
@@ -72,13 +73,16 @@ class YandexStorageAccessor(
try {
scanSizeAndNumOfFiles()
_storageReady.value = true
Log.d(TAG, "init ok storageUuid=$storageUuid")
} catch (e: YandexDiskAuthException) {
reportAuthFailure()
_storageReady.value = false
Log.w(TAG, "init auth failed storageUuid=$storageUuid", e)
throw e
} catch (_: Exception) {
} catch (e: Exception) {
_storageReady.value = false
throw Exception("Yandex storage init failed")
Log.w(TAG, "init failed storageUuid=$storageUuid", e)
throw Exception("Yandex storage init failed", e)
}
}
@@ -432,6 +436,7 @@ class YandexStorageAccessor(
}
companion object {
private const val TAG = "YandexStorageAcc"
private const val SYSTEM_HIDDEN_DIRNAME = "wallenc-yandex-system"
private const val DATA_PAGE_LENGTH = 10
private const val API_LIST_LIMIT = 200

View File

@@ -1,6 +1,6 @@
package com.github.nullptroma.wallenc.data.vaults.yandex
import com.github.nullptroma.wallenc.data.network.yandexdisk.repository.YandexDiskAuthException
import com.github.nullptroma.wallenc.data.network.yandexdisk.YandexDiskAuthException
import com.github.nullptroma.wallenc.data.network.yandexdisk.repository.YandexDiskRepository
import com.github.nullptroma.wallenc.data.storages.yandex.YandexStorage
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
@@ -12,6 +12,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import android.util.Log
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.UUID
@@ -64,12 +65,15 @@ class YandexVault(
_availableSpace.value = (total - used).coerceAtLeast(0L)
_vaultReachable.value = true
_storages.value = loadStoragesList()
} catch (_: YandexDiskAuthException) {
Log.d(TAG, "refresh ok uuid=$uuid storages=${_storages.value.size}")
} catch (e: YandexDiskAuthException) {
_vaultReachable.value = false
_storages.value = emptyList()
} catch (_: Exception) {
Log.w(TAG, "refresh auth failed uuid=$uuid: ${e.message}")
} catch (e: Exception) {
_vaultReachable.value = false
_storages.value = emptyList()
Log.w(TAG, "refresh failed uuid=$uuid", e)
}
}
@@ -96,8 +100,8 @@ class YandexVault(
try {
storage.init()
out.add(storage)
} catch (_: Exception) {
// пропускаем битое/частично созданное хранилище
} catch (e: Exception) {
Log.w(TAG, "skip broken storage uuid=$storageUuid: ${e.message}")
}
}
if (items.size < APP_LIST_LIMIT) break
@@ -108,6 +112,7 @@ class YandexVault(
override suspend fun createStorage(): IStorage = withContext(ioDispatcher) {
val id = UUID.randomUUID()
Log.d(TAG, "createStorage start vault=$uuid storage=$id")
repo.createFolder("app:/$id")
val storage = YandexStorage(
uuid = id,
@@ -121,6 +126,7 @@ class YandexVault(
)
storage.init()
_storages.value = _storages.value + storage
Log.d(TAG, "createStorage done storage=$id")
storage
}
@@ -132,11 +138,13 @@ class YandexVault(
override suspend fun remove(storage: IStorage) = withContext(ioDispatcher) {
if (storage !is YandexStorage) return@withContext
Log.d(TAG, "remove storage=${storage.uuid}")
repo.delete("app:/${storage.uuid}", permanently = true)
_storages.value = _storages.value.filter { it.uuid != storage.uuid }
}
private companion object {
private const val TAG = "YandexVault"
private const val APP_LIST_LIMIT = 200
}
}