Исправлено много варнингов

This commit is contained in:
2026-05-11 22:18:15 +03:00
parent d176f2a464
commit 61bcaa95d8
29 changed files with 162 additions and 123 deletions

View File

@@ -6,9 +6,9 @@ import java.time.Instant
@JsonIgnoreProperties(ignoreUnknown = true)
data class DiskInfoDto(
@JsonProperty("trash_size") val trashSize: Long? = null,
@JsonProperty("total_space") val totalSpace: Long? = null,
@JsonProperty("used_space") val usedSpace: Long? = null,
@param:JsonProperty("trash_size") val trashSize: Long? = null,
@param:JsonProperty("total_space") val totalSpace: Long? = null,
@param:JsonProperty("used_space") val usedSpace: Long? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -36,10 +36,10 @@ data class ResourceDto(
val size: Long? = null,
val modified: Instant? = null,
val created: Instant? = null,
@JsonProperty("mime_type") val mimeType: String? = null,
@param:JsonProperty("mime_type") val mimeType: String? = null,
val md5: String? = null,
@JsonProperty("custom_properties") val customProperties: Map<String, Any?>? = null,
@JsonProperty("_embedded") val embedded: EmbeddedResourceListDto? = null,
@param:JsonProperty("custom_properties") val customProperties: Map<String, Any?>? = null,
@param:JsonProperty("_embedded") val embedded: EmbeddedResourceListDto? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -56,5 +56,5 @@ data class ApiErrorDto(
@JsonIgnoreProperties(ignoreUnknown = true)
data class CustomPropertiesPatchDto(
@JsonProperty("custom_properties") val customProperties: Map<String, String>,
@param:JsonProperty("custom_properties") val customProperties: Map<String, String>,
)

View File

@@ -13,7 +13,6 @@ import com.github.nullptroma.wallenc.infrastructure.network.yandexdisk.dto.Resou
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
@@ -21,6 +20,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import retrofit2.HttpException
import retrofit2.Response
import java.io.FilterInputStream
import java.io.IOException
import java.io.InputStream
@@ -74,20 +74,6 @@ class YandexDiskRepository(
}
}
suspend fun move(from: String, toPath: String, overwrite: Boolean = false): Unit =
withContext(ioDispatcher) {
val resp = wrapAuth { api.moveResource(from, toPath, overwrite) }
when (resp.code()) {
201 -> Unit
202 -> {
val link = resp.body()?.use { body -> parseLink(body) }
?: throw IOException("MOVE 202 without body")
awaitOperation(link.href)
}
else -> throw failure("move", resp)
}
}
suspend fun setCustomProperties(path: String, props: Map<String, String>): Unit =
withContext(ioDispatcher) {
val resp = wrapAuth {
@@ -141,21 +127,17 @@ class YandexDiskRepository(
resp.close()
throw IOException("Download failed: HTTP ${resp.code}")
}
val body = resp.body ?: run {
val body = resp.body
val stream = body?.byteStream() ?: run {
resp.close()
throw IOException("Download: empty body")
throw IOException("Download failed: missing body")
}
body.byteStream().let { stream ->
object : InputStream() {
override fun read(): Int = stream.read()
override fun read(b: ByteArray): Int = stream.read(b)
override fun read(b: ByteArray, off: Int, len: Int): Int = stream.read(b, off, len)
override fun close() {
try {
stream.close()
} finally {
resp.close()
}
object : FilterInputStream(stream) {
override fun close() {
try {
`in`.close()
} finally {
resp.close()
}
}
}
@@ -201,16 +183,5 @@ class YandexDiskRepository(
private val OCTET_STREAM = "application/octet-stream".toMediaType()
private const val OPERATION_POLL_DELAY_MS = 300L
private const val OPERATION_POLL_MAX = 200
fun parseOperationId(href: String): String? {
val url = href.toHttpUrlOrNull() ?: return null
url.queryParameter("id")?.let { return it }
val segments = url.pathSegments
val idx = segments.indexOf("operations")
if (idx >= 0 && idx + 1 < segments.size) {
return segments[idx + 1]
}
return null
}
}
}

View File

@@ -18,10 +18,10 @@ import java.io.InputStream
import java.util.UUID
/**
* Общий «скелет» storage'а: единая логика meta-info, rename, setEncInfo,
* clearAllContent и делегирования размера/доступности к [accessor].
* Общий «скелет» для [IStorage]: единая логика meta-info, rename, setEncInfo,
* clearAllContent и делегирование размеров и доступности в [accessor].
*
* Подклассы определяют только как создаётся [accessor], значение
* Подклассы определяют только способ создания [accessor], значение
* [isVirtualStorage] и (при необходимости) расширяют [init] своими шагами
* (например, проверкой ключа или инициализацией внешней связи).
*/
@@ -60,8 +60,8 @@ abstract class BaseStorage(
protected open fun metaInfoUuidPart(): String = uuid.toString()
/**
* Запускается единожды при старте storage'а. Подклассы могут переопределить,
* добавив свои шаги (init accessor'а, проверка ключа и т.п.). Обязательно
* Запускается единожды при первом использовании хранилища. Подклассы могут переопределить,
* добавив свои шаги (инициализацию [accessor], проверку ключа и т.п.). Обязательно
* должен в какой-то момент вызвать [readMetaInfo].
*/
open suspend fun init() {

View File

@@ -34,10 +34,10 @@ import java.time.Instant
import java.util.UUID
/**
* [IStorageAccessor] поверх папки приложения `app:/<storageUuid>/…` на Яндекс.Диске.
* Реализация [IStorageAccessor] для дерева файлов `app:/<storageUuid>/…` на Яндекс.Диске.
*
* [isAvailable] = доступность vault'а ([vaultAvailability]) **и** успешная локальная
* инициализация этого storage ([storageReady]).
* [isAvailable] объединяет доступность удалённого хранилища ([vaultAvailability])
* и успешную локальную инициализацию ([storageReady]) этого аксессора.
*/
class YandexStorageAccessor(
private val storageUuid: UUID,
@@ -265,7 +265,7 @@ class YandexStorageAccessor(
while (queue.isNotEmpty()) {
val rel = queue.removeFirst()
if (isSystemRel(rel)) continue
val (files, dirs) = listImmediateChildren(rel)
val (_, dirs) = listImmediateChildren(rel)
for (d in dirs) {
if (!isSystemRel(d.metaInfo.path)) {
out.add(d)
@@ -402,10 +402,12 @@ class YandexStorageAccessor(
override suspend fun openWriteSystemFile(name: String): OutputStream = withContext(ioDispatcher) {
ensureSystemDirExists()
val rel = "/$SYSTEM_HIDDEN_DIRNAME/$name"
val baos = ByteArrayOutputStream()
baos.onClosed {
val uploadBuffer = ByteArrayOutputStream()
uploadBuffer.onClosed {
runBlocking(ioDispatcher) {
guard { repo.uploadBytes(toDiskPath(rel), baos.toByteArray(), overwrite = true) }
guard {
repo.uploadBytes(toDiskPath(rel), uploadBuffer.toByteArray(), overwrite = true)
}
}
}
}

View File

@@ -31,7 +31,7 @@ import java.util.UUID
@OptIn(ExperimentalCoroutinesApi::class)
class VaultsManager(
private val ioDispatcher: CoroutineDispatcher,
localVault: IVault,
private val localVault: IVault,
keyRepo: StorageKeyMapStore,
private val yandexAccountStore: YandexAccountStore,
private val yandexUserInfoRepository: YandexUserInfoRepository,
@@ -40,8 +40,6 @@ class VaultsManager(
private val scope = CoroutineScope(SupervisorJob() + ioDispatcher)
private val localVault: IVault = localVault
private val yandexVaults: StateFlow<List<IVault>> = yandexAccountStore.observeAll()
.map { rows ->
rows.map { row ->

View File

@@ -20,7 +20,7 @@ import kotlin.io.path.pathString
class LocalVault(
private val ioDispatcher: CoroutineDispatcher,
private val vaultRoot: File?,
vaultRoot: File?,
) : DescribedVault {
override val uuid: UUID = vaultRoot?.let { root ->
@@ -42,7 +42,7 @@ class LocalVault(
private val _availableSpace = MutableStateFlow<Long?>(null)
override val availableSpace: StateFlow<Long?> = _availableSpace
private val path = MutableStateFlow<File?>(vaultRoot)
private val path = MutableStateFlow(vaultRoot)
init {
CoroutineScope(ioDispatcher).launch {

View File

@@ -1,15 +1,13 @@
package com.github.nullptroma.wallenc.infrastructure.vaults.yandex
import com.github.nullptroma.wallenc.vault.contract.CloudBrand
import com.github.nullptroma.wallenc.vault.contract.VaultRegistration
/**
* Регистрация удалённого vault'а Яндекс.Диска по результату OAuth.
* Регистрация удалённого хранилища Яндекс.Диска по результату OAuth.
*
* Живёт в `:data` (а не в `:vault-api`), потому что [VaultRegistration]
* намеренно не sealed — конкретные реализации лежат рядом со своим поставщиком.
* presentation никогда не открывает этот тип, только перепасовывает обратно
* в `VaultRegistrar.register(...)`.
* Слой presentation не раскрывает этот тип, только передаёт его в `VaultRegistrar.register(...)`.
*/
data class YandexRegistration(
val oauthToken: String,
@@ -17,6 +15,4 @@ data class YandexRegistration(
init {
require(oauthToken.isNotBlank()) { "oauthToken must not be blank" }
}
val brand: CloudBrand get() = CloudBrand.YANDEX
}

View File

@@ -64,10 +64,10 @@ class YandexVault(
_availableSpace.value = (total - used).coerceAtLeast(0L)
_vaultReachable.value = true
_storages.value = loadStoragesList()
} catch (e: YandexDiskAuthException) {
} catch (_: YandexDiskAuthException) {
_vaultReachable.value = false
_storages.value = emptyList()
} catch (e: Exception) {
} catch (_: Exception) {
_vaultReachable.value = false
_storages.value = emptyList()
}
@@ -118,7 +118,7 @@ class YandexVault(
},
)
storage.init()
_storages.value = _storages.value + storage
_storages.value += storage
storage
}