-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
7 changed files
with
722 additions
and
589 deletions.
There are no files selected for viewing
187 changes: 187 additions & 0 deletions
187
app/src/main/java/org/zotero/android/screens/share/ShareErrorProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
package org.zotero.android.screens.share | ||
|
||
import android.content.Context | ||
import org.zotero.android.BuildConfig | ||
import org.zotero.android.api.network.CustomResult | ||
import org.zotero.android.database.DbWrapper | ||
import org.zotero.android.database.requests.ReadGroupDbRequest | ||
import org.zotero.android.sync.LibraryIdentifier | ||
import org.zotero.android.sync.Parsing | ||
import org.zotero.android.sync.SchemaError | ||
import org.zotero.android.translator.data.AttachmentState | ||
import org.zotero.android.translator.data.TranslationWebViewError | ||
import org.zotero.android.uicomponents.Strings | ||
import timber.log.Timber | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
class ShareErrorProcessor @Inject constructor( | ||
private val context: Context, | ||
private val dbWrapper: DbWrapper | ||
) { | ||
fun errorMessage(error: AttachmentState.Error): String? { | ||
return when (error) { | ||
AttachmentState.Error.apiFailure -> { | ||
context.getString(Strings.errors_shareext_api_error) | ||
} | ||
|
||
AttachmentState.Error.cantLoadSchema -> { | ||
context.getString(Strings.errors_shareext_cant_load_schema) | ||
} | ||
|
||
AttachmentState.Error.cantLoadWebData -> { | ||
context.getString(Strings.errors_shareext_cant_load_data) | ||
} | ||
|
||
AttachmentState.Error.downloadFailed -> { | ||
context.getString(Strings.errors_shareext_download_failed) | ||
} | ||
|
||
AttachmentState.Error.downloadedFileNotPdf -> { | ||
null | ||
} | ||
|
||
AttachmentState.Error.expired -> { | ||
context.getString(Strings.errors_shareext_unknown) | ||
} | ||
|
||
AttachmentState.Error.fileMissing -> { | ||
context.getString(Strings.errors_shareext_missing_file) | ||
} | ||
|
||
AttachmentState.Error.itemsNotFound -> { | ||
context.getString(Strings.errors_shareext_items_not_found) | ||
} | ||
|
||
AttachmentState.Error.md5Missing -> { | ||
null | ||
} | ||
|
||
AttachmentState.Error.mtimeMissing -> { | ||
null | ||
} | ||
|
||
is AttachmentState.Error.parseError -> { | ||
context.getString(Strings.errors_shareext_parsing_error) | ||
} | ||
|
||
is AttachmentState.Error.quotaLimit -> { | ||
when (error.libraryIdentifier) { | ||
is LibraryIdentifier.custom -> { | ||
context.getString(Strings.errors_shareext_personal_quota_reached) | ||
} | ||
|
||
is LibraryIdentifier.group -> { | ||
val groupId = error.libraryIdentifier.groupId | ||
val group = | ||
dbWrapper.realmDbStorage.perform(ReadGroupDbRequest(identifier = groupId)) | ||
val groupName = group?.name ?: "$groupId" | ||
return context.getString( | ||
Strings.errors_shareext_group_quota_reached, | ||
groupName | ||
) | ||
} | ||
} | ||
} | ||
|
||
is AttachmentState.Error.schemaError -> { | ||
context.getString(Strings.errors_shareext_schema_error) | ||
} | ||
|
||
AttachmentState.Error.unknown -> { | ||
context.getString(Strings.errors_shareext_unknown) | ||
} | ||
|
||
AttachmentState.Error.webDavFailure -> { | ||
context.getString(Strings.errors_shareext_webdav_error) | ||
} | ||
|
||
AttachmentState.Error.webDavNotVerified -> { | ||
context.getString(Strings.errors_shareext_webdav_not_verified) | ||
} | ||
|
||
is AttachmentState.Error.webViewError -> { | ||
return when (error.error) { | ||
TranslationWebViewError.cantFindFile -> { | ||
context.getString(Strings.errors_shareext_missing_base_files) | ||
} | ||
|
||
TranslationWebViewError.incompatibleItem -> { | ||
context.getString(Strings.errors_shareext_incompatible_item) | ||
} | ||
|
||
TranslationWebViewError.javascriptCallMissingResult -> { | ||
context.getString(Strings.errors_shareext_javascript_failed) | ||
} | ||
|
||
TranslationWebViewError.noSuccessfulTranslators -> { | ||
null | ||
} | ||
|
||
TranslationWebViewError.webExtractionMissingData -> { | ||
context.getString(Strings.errors_shareext_response_missing_data) | ||
} | ||
|
||
TranslationWebViewError.webExtractionMissingJs -> { | ||
context.getString(Strings.errors_shareext_missing_base_files) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
fun attachmentError( | ||
generalError: CustomResult.GeneralError, | ||
libraryId: LibraryIdentifier? | ||
): AttachmentState.Error { | ||
when (generalError) { | ||
is CustomResult.GeneralError.CodeError -> { | ||
val error = generalError.throwable | ||
if (error is AttachmentState.Error) { | ||
return error | ||
} | ||
if (error is Parsing.Error) { | ||
Timber.e(error, "ExtensionViewModel: could not parse item") | ||
return AttachmentState.Error.parseError(error) | ||
} | ||
|
||
if (error is SchemaError) { | ||
Timber.e(error, "ExtensionViewModel: schema failed") | ||
return AttachmentState.Error.schemaError(error) | ||
} | ||
if (error is TranslationWebViewError) { | ||
return AttachmentState.Error.webViewError(error) | ||
} | ||
} | ||
|
||
is CustomResult.GeneralError.NetworkError -> { | ||
return networkErrorRequiresAbort( | ||
error = generalError, | ||
url = BuildConfig.BASE_API_URL, | ||
libraryId = libraryId | ||
) | ||
} | ||
} | ||
return AttachmentState.Error.unknown | ||
} | ||
|
||
private fun networkErrorRequiresAbort( | ||
error: CustomResult.GeneralError.NetworkError, | ||
url: String?, | ||
libraryId: LibraryIdentifier? | ||
): AttachmentState.Error { | ||
val defaultError = if ((url ?: "").contains(BuildConfig.BASE_API_URL)) { | ||
AttachmentState.Error.apiFailure | ||
} else { | ||
AttachmentState.Error.webDavFailure | ||
} | ||
|
||
val code = error.httpCode | ||
if (code == 413 && libraryId != null) { | ||
return AttachmentState.Error.quotaLimit(libraryId) | ||
} | ||
return defaultError | ||
} | ||
|
||
} |
89 changes: 89 additions & 0 deletions
89
app/src/main/java/org/zotero/android/screens/share/ShareFileDownloader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.zotero.android.screens.share | ||
|
||
import com.google.common.io.ByteProcessor | ||
import com.google.common.io.ByteStreams | ||
import com.google.common.io.Closeables | ||
import org.zotero.android.api.NoAuthenticationApi | ||
import org.zotero.android.api.network.CustomResult | ||
import org.zotero.android.api.network.safeApiCall | ||
import timber.log.Timber | ||
import java.io.File | ||
import java.io.FileOutputStream | ||
import java.io.IOException | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
class ShareFileDownloader @Inject constructor( | ||
private val noAuthenticationApi: NoAuthenticationApi | ||
) { | ||
|
||
suspend fun download( | ||
url: String, | ||
file: File, | ||
cookies: String?, | ||
userAgent: String?, | ||
referrer: String?, | ||
updateProgressBar: (progress: Int) -> Unit, | ||
) { | ||
val headers: MutableMap<String, String> = LinkedHashMap() | ||
if (userAgent != null) { | ||
headers["User-Agent"] = userAgent | ||
} | ||
if (referrer != null) { | ||
headers["Referer"] = referrer | ||
} | ||
if (cookies != null) { | ||
headers["Cookie"] = cookies | ||
} | ||
val networkResult = safeApiCall { | ||
noAuthenticationApi.downloadFileStreaming(url = url, headers = headers) | ||
} | ||
when (networkResult) { | ||
is CustomResult.GeneralSuccess -> { | ||
val byteStream = networkResult.value!!.byteStream() | ||
val total = networkResult.value!!.contentLength() | ||
var progress = 0L | ||
val out = FileOutputStream(file); | ||
try { | ||
ByteStreams.readBytes(byteStream, | ||
object : ByteProcessor<Void?> { | ||
@Throws(IOException::class) | ||
override fun processBytes( | ||
buffer: ByteArray, | ||
offset: Int, | ||
length: Int | ||
): Boolean { | ||
out.write(buffer, offset, length) | ||
progress += length | ||
val progressResult = (progress / total.toDouble() * 100).toInt() | ||
if (progressResult > 0) { | ||
println() | ||
} | ||
updateProgressBar(progressResult) | ||
return true | ||
} | ||
|
||
override fun getResult(): Void? { | ||
return null | ||
} | ||
}) | ||
} catch (e: Exception) { | ||
Timber.e(e, "Could not download $url") | ||
throw e | ||
} finally { | ||
Closeables.close(out, true) | ||
} | ||
} | ||
|
||
is CustomResult.GeneralError.CodeError -> { | ||
throw networkResult.throwable | ||
} | ||
|
||
is CustomResult.GeneralError.NetworkError -> { | ||
throw Exception(networkResult.stringResponse) | ||
} | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.