mobile: archive import errors (#2496)

This commit is contained in:
spaced4ndy
2023-05-24 14:22:12 +04:00
committed by GitHub
parent de33fedea4
commit a1e6d90e31
7 changed files with 55 additions and 14 deletions

View File

@@ -545,9 +545,9 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
throw Error("failed to export archive: ${r.responseType} ${r.details}")
}
suspend fun apiImportArchive(config: ArchiveConfig) {
suspend fun apiImportArchive(config: ArchiveConfig): List<ArchiveError> {
val r = sendCmd(CC.ApiImportArchive(config))
if (r is CR.CmdOk) return
if (r is CR.ArchiveImported) return r.archiveErrors
throw Error("failed to import archive: ${r.responseType} ${r.details}")
}
@@ -3369,6 +3369,7 @@ sealed class CR {
@Serializable @SerialName("cmdOk") class CmdOk(val user: User?): CR()
@Serializable @SerialName("chatCmdError") class ChatCmdError(val user_: User?, val chatError: ChatError): CR()
@Serializable @SerialName("chatError") class ChatRespError(val user_: User?, val chatError: ChatError): CR()
@Serializable @SerialName("archiveImported") class ArchiveImported(val archiveErrors: List<ArchiveError>): CR()
@Serializable class Response(val type: String, val json: String): CR()
@Serializable class Invalid(val str: String): CR()
@@ -3478,6 +3479,7 @@ sealed class CR {
is CmdOk -> "cmdOk"
is ChatCmdError -> "chatCmdError"
is ChatRespError -> "chatError"
is ArchiveImported -> "archiveImported"
is Response -> "* $type"
is Invalid -> "* invalid json"
}
@@ -3590,6 +3592,7 @@ sealed class CR {
is CmdOk -> withUser(user, noDetails())
is ChatCmdError -> withUser(user_, chatError.string)
is ChatRespError -> withUser(user_, chatError.string)
is ArchiveImported -> "${archiveErrors.map { it.string } }"
is Response -> json
is Invalid -> str
}
@@ -3678,6 +3681,7 @@ sealed class ChatErrorType {
is InvalidConnReq -> "invalidConnReq"
is FileAlreadyReceiving -> "fileAlreadyReceiving"
is СommandError -> "commandError $message"
is CEException -> "exception $message"
}
@Serializable @SerialName("noActiveUser") class NoActiveUser: ChatErrorType()
@Serializable @SerialName("differentActiveUser") class DifferentActiveUser: ChatErrorType()
@@ -3685,6 +3689,7 @@ sealed class ChatErrorType {
@Serializable @SerialName("invalidConnReq") class InvalidConnReq: ChatErrorType()
@Serializable @SerialName("fileAlreadyReceiving") class FileAlreadyReceiving: ChatErrorType()
@Serializable @SerialName("commandError") class СommandError(val message: String): ChatErrorType()
@Serializable @SerialName("exception") class CEException(val message: String): ChatErrorType()
}
@Serializable
@@ -3896,3 +3901,13 @@ sealed class XFTPErrorType {
@Serializable @SerialName("FILE_IO") object FILE_IO: XFTPErrorType()
@Serializable @SerialName("INTERNAL") object INTERNAL: XFTPErrorType()
}
@Serializable
sealed class ArchiveError {
val string: String get() = when (this) {
is ArchiveErrorImport -> "import ${chatError.string}"
is ArchiveErrorImportFile -> "importFile $file ${chatError.string}"
}
@Serializable @SerialName("import") class ArchiveErrorImport(val chatError: ChatError): ArchiveError()
@Serializable @SerialName("importFile") class ArchiveErrorImportFile(val file: String, val chatError: ChatError): ArchiveError()
}

View File

@@ -178,8 +178,7 @@ fun DatabaseLayout(
val unencrypted = chatDbEncrypted == false
SettingsActionItem(
if (unencrypted) painterResource(R.drawable.ic_lock_open) else if (useKeyChain) painterResource(R.drawable.ic_vpn_key_filled)
else painterResource(R
.drawable.ic_lock),
else painterResource(R.drawable.ic_lock),
stringResource(R.string.database_passphrase),
click = showSettingsModal() { DatabaseEncryptionView(it) },
iconColor = if (unencrypted) WarningOrange else MaterialTheme.colors.secondary,
@@ -574,11 +573,17 @@ private fun importArchive(
m.controller.apiDeleteStorage()
try {
val config = ArchiveConfig(archivePath, parentTempDirectory = context.cacheDir.toString())
m.controller.apiImportArchive(config)
val archiveErrors = m.controller.apiImportArchive(config)
DatabaseUtils.ksDatabasePassword.remove()
appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory(context))
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), generalGetString(R.string.restart_the_app_to_use_imported_chat_database))
if (archiveErrors.isEmpty()) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database))
}
} else {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(R.string.non_fatal_errors_occured_during_import))
}
}
} catch (e: Error) {
operationEnded(m, progressIndicator) {

View File

@@ -892,6 +892,7 @@
<string name="error_importing_database">Error importing chat database</string>
<string name="chat_database_imported">Chat database imported</string>
<string name="restart_the_app_to_use_imported_chat_database">Restart the app to use imported chat database.</string>
<string name="non_fatal_errors_occured_during_import">Some non-fatal errors occurred during import - you may see Chat console for more details.</string>
<string name="delete_chat_profile_question">Delete chat profile?</string>
<string name="delete_chat_profile_action_cannot_be_undone_warning">This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost.</string>
<string name="chat_database_deleted">Chat database deleted</string>

View File

@@ -243,8 +243,10 @@ func apiExportArchive(config: ArchiveConfig) async throws {
try await sendCommandOkResp(.apiExportArchive(config: config))
}
func apiImportArchive(config: ArchiveConfig) async throws {
try await sendCommandOkResp(.apiImportArchive(config: config))
func apiImportArchive(config: ArchiveConfig) async throws -> [ArchiveError] {
let r = await chatSendCmd(.apiImportArchive(config: config))
if case let .archiveImported(archiveErrors) = r { return archiveErrors }
throw r
}
func apiDeleteStorage() async throws {
@@ -538,7 +540,6 @@ func apiConnect_(connReq: String) async -> (ConnReqType?, Alert?) {
return (nil, nil)
}
let r = await chatSendCmd(.apiConnect(userId: userId, connReq: connReq))
let am = AlertManager.shared
switch r {
case .sentConfirmation: return (.invitation, nil)
case .sentInvitation: return (.contact, nil)

View File

@@ -14,6 +14,7 @@ enum DatabaseAlert: Identifiable {
case exportProhibited
case importArchive
case archiveImported
case archiveImportedWithErrors(archiveErrors: [ArchiveError])
case deleteChat
case chatDeleted
case deleteLegacyDatabase
@@ -27,6 +28,7 @@ enum DatabaseAlert: Identifiable {
case .exportProhibited: return "exportProhibited"
case .importArchive: return "importArchive"
case .archiveImported: return "archiveImported"
case .archiveImportedWithErrors: return "archiveImportedWithErrors"
case .deleteChat: return "deleteChat"
case .chatDeleted: return "chatDeleted"
case .deleteLegacyDatabase: return "deleteLegacyDatabase"
@@ -251,7 +253,11 @@ struct DatabaseView: View {
title: Text("Chat database imported"),
message: Text("Restart the app to use imported chat database")
)
case .archiveImportedWithErrors:
return Alert(
title: Text("Chat database imported"),
message: Text("Restart the app to use imported chat database") + Text("\n") + Text("Some non-fatal errors occurred during import - you may see Chat console for more details.")
)
case .deleteChat:
return Alert(
title: Text("Delete chat profile?"),
@@ -351,9 +357,13 @@ struct DatabaseView: View {
try await apiDeleteStorage()
do {
let config = ArchiveConfig(archivePath: archivePath.path)
try await apiImportArchive(config: config)
let archiveErrors = try await apiImportArchive(config: config)
_ = kcDatabasePassword.remove()
await operationEnded(.archiveImported)
if archiveErrors.isEmpty {
await operationEnded(.archiveImported)
} else {
await operationEnded(.archiveImportedWithErrors(archiveErrors: archiveErrors))
}
} catch let error {
await operationEnded(.error(title: "Error importing chat database", error: responseError(error)))
}

View File

@@ -203,7 +203,7 @@ struct MigrateToAppGroupView: View {
dbContainerGroupDefault.set(.group)
resetChatCtrl()
try await MainActor.run { try initializeChat(start: false) }
try await apiImportArchive(config: config)
let _ = try await apiImportArchive(config: config)
await MainActor.run { setV3DBMigration(.migrated) }
} catch let error {
dbContainerGroupDefault.set(.documents)

View File

@@ -495,6 +495,7 @@ public enum ChatResponse: Decodable, Error {
case cmdOk(user: User?)
case chatCmdError(user_: User?, chatError: ChatError)
case chatError(user_: User?, chatError: ChatError)
case archiveImported(archiveErrors: [ArchiveError])
public var responseType: String {
get {
@@ -609,6 +610,7 @@ public enum ChatResponse: Decodable, Error {
case .cmdOk: return "cmdOk"
case .chatCmdError: return "chatCmdError"
case .chatError: return "chatError"
case .archiveImported: return "archiveImported"
}
}
}
@@ -726,6 +728,7 @@ public enum ChatResponse: Decodable, Error {
case .cmdOk: return noDetails
case let .chatCmdError(u, chatError): return withUser(u, String(describing: chatError))
case let .chatError(u, chatError): return withUser(u, String(describing: chatError))
case let .archiveImported(archiveErrors): return String(describing: archiveErrors)
}
}
}
@@ -1248,6 +1251,7 @@ public enum ChatErrorType: Decodable {
case invalidChatItemDelete
case agentVersion
case commandError(message: String)
case exception(message: String)
}
public enum StoreError: Decodable {
@@ -1386,3 +1390,8 @@ public enum SMPAgentError: Decodable {
case A_VERSION
case A_ENCRYPTION
}
public enum ArchiveError: Decodable {
case `import`(chatError: ChatError)
case importFile(file: String, chatError: ChatError)
}