|
|
@ -1,16 +1,24 @@
|
|
|
|
package org.session.libsession.messaging.jobs
|
|
|
|
package org.session.libsession.messaging.jobs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.content.ContentResolver
|
|
|
|
|
|
|
|
import android.media.MediaDataSource
|
|
|
|
|
|
|
|
import android.media.MediaExtractor
|
|
|
|
import okhttp3.HttpUrl
|
|
|
|
import okhttp3.HttpUrl
|
|
|
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
|
|
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
|
|
|
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
|
|
|
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
|
|
|
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
|
|
|
|
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
|
|
|
|
|
|
|
|
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
|
|
|
|
import org.session.libsession.messaging.utilities.Data
|
|
|
|
import org.session.libsession.messaging.utilities.Data
|
|
|
|
|
|
|
|
import org.session.libsession.snode.OnionRequestAPI
|
|
|
|
|
|
|
|
import org.session.libsession.utilities.DecodedAudio
|
|
|
|
import org.session.libsession.utilities.DownloadUtilities
|
|
|
|
import org.session.libsession.utilities.DownloadUtilities
|
|
|
|
|
|
|
|
import org.session.libsession.utilities.InputStreamMediaDataSource
|
|
|
|
import org.session.libsignal.streams.AttachmentCipherInputStream
|
|
|
|
import org.session.libsignal.streams.AttachmentCipherInputStream
|
|
|
|
import org.session.libsignal.utilities.Base64
|
|
|
|
import org.session.libsignal.utilities.Base64
|
|
|
|
import org.session.libsignal.utilities.Log
|
|
|
|
import org.session.libsignal.utilities.Log
|
|
|
|
import java.io.File
|
|
|
|
import java.io.File
|
|
|
|
import java.io.FileInputStream
|
|
|
|
import java.io.FileInputStream
|
|
|
|
|
|
|
|
import java.io.InputStream
|
|
|
|
|
|
|
|
|
|
|
|
class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) : Job {
|
|
|
|
class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) : Job {
|
|
|
|
override var delegate: JobDelegate? = null
|
|
|
|
override var delegate: JobDelegate? = null
|
|
|
@ -37,46 +45,64 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
|
|
|
val storage = MessagingModuleConfiguration.shared.storage
|
|
|
|
val storage = MessagingModuleConfiguration.shared.storage
|
|
|
|
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
|
|
|
|
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
|
|
|
|
val handleFailure: (java.lang.Exception) -> Unit = { exception ->
|
|
|
|
val handleFailure: (java.lang.Exception) -> Unit = { exception ->
|
|
|
|
if (exception == Error.NoAttachment) {
|
|
|
|
if (exception == Error.NoAttachment
|
|
|
|
|
|
|
|
|| (exception is OnionRequestAPI.HTTPRequestFailedAtDestinationException && exception.statusCode == 400)) {
|
|
|
|
messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
|
|
|
messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
|
|
|
this.handlePermanentFailure(exception)
|
|
|
|
this.handlePermanentFailure(exception)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
this.handleFailure(exception)
|
|
|
|
this.handleFailure(exception)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var tempFile: File? = null
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID)
|
|
|
|
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID)
|
|
|
|
?: return handleFailure(Error.NoAttachment)
|
|
|
|
?: return handleFailure(Error.NoAttachment)
|
|
|
|
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachmentID, this.databaseMessageID)
|
|
|
|
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachmentID, this.databaseMessageID)
|
|
|
|
val tempFile = createTempFile()
|
|
|
|
tempFile = createTempFile()
|
|
|
|
val threadID = storage.getThreadIdForMms(databaseMessageID)
|
|
|
|
val threadID = storage.getThreadIdForMms(databaseMessageID)
|
|
|
|
val openGroupV2 = storage.getV2OpenGroup(threadID)
|
|
|
|
val openGroupV2 = storage.getV2OpenGroup(threadID)
|
|
|
|
val inputStream = if (openGroupV2 == null) {
|
|
|
|
if (openGroupV2 == null) {
|
|
|
|
DownloadUtilities.downloadFile(tempFile, attachment.url)
|
|
|
|
DownloadUtilities.downloadFile(tempFile, attachment.url)
|
|
|
|
// Assume we're retrieving an attachment for an open group server if the digest is not set
|
|
|
|
|
|
|
|
if (attachment.digest?.size ?: 0 == 0 || attachment.key.isNullOrEmpty()) {
|
|
|
|
|
|
|
|
FileInputStream(tempFile)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
AttachmentCipherInputStream.createForAttachment(tempFile, attachment.size, Base64.decode(attachment.key), attachment.digest)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
val url = HttpUrl.parse(attachment.url)!!
|
|
|
|
val url = HttpUrl.parse(attachment.url)!!
|
|
|
|
val fileID = url.pathSegments().last()
|
|
|
|
val fileID = url.pathSegments().last()
|
|
|
|
OpenGroupAPIV2.download(fileID.toLong(), openGroupV2.room, openGroupV2.server).get().let {
|
|
|
|
OpenGroupAPIV2.download(fileID.toLong(), openGroupV2.room, openGroupV2.server).get().let {
|
|
|
|
tempFile.writeBytes(it)
|
|
|
|
tempFile.writeBytes(it)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FileInputStream(tempFile)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
val inputStream = getInputStream(tempFile, attachment)
|
|
|
|
|
|
|
|
|
|
|
|
messageDataProvider.insertAttachment(databaseMessageID, attachment.attachmentId, inputStream)
|
|
|
|
messageDataProvider.insertAttachment(databaseMessageID, attachment.attachmentId, inputStream)
|
|
|
|
|
|
|
|
if (attachment.contentType.startsWith("audio/")) {
|
|
|
|
|
|
|
|
// process the duration
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
InputStreamMediaDataSource(getInputStream(tempFile, attachment)).use { mediaDataSource ->
|
|
|
|
|
|
|
|
val durationMs = (DecodedAudio.create(mediaDataSource).totalDuration / 1000.0).toLong()
|
|
|
|
|
|
|
|
messageDataProvider.updateAudioAttachmentDuration(attachment.attachmentId, durationMs)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
Log.e("Loki", "Couldn't process audio attachment", e)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
tempFile.delete()
|
|
|
|
tempFile.delete()
|
|
|
|
handleSuccess()
|
|
|
|
handleSuccess()
|
|
|
|
} catch (e: Exception) {
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
tempFile?.delete()
|
|
|
|
return handleFailure(e)
|
|
|
|
return handleFailure(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun getInputStream(tempFile: File, attachment: DatabaseAttachment): InputStream {
|
|
|
|
|
|
|
|
// Assume we're retrieving an attachment for an open group server if the digest is not set
|
|
|
|
|
|
|
|
return if (attachment.digest?.size ?: 0 == 0 || attachment.key.isNullOrEmpty()) {
|
|
|
|
|
|
|
|
FileInputStream(tempFile)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
AttachmentCipherInputStream.createForAttachment(tempFile, attachment.size, Base64.decode(attachment.key), attachment.digest)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun handleSuccess() {
|
|
|
|
private fun handleSuccess() {
|
|
|
|
Log.w(AttachmentUploadJob.TAG, "Attachment downloaded successfully.")
|
|
|
|
Log.w("AttachmentDownloadJob", "Attachment downloaded successfully.")
|
|
|
|
delegate?.handleJobSucceeded(this)
|
|
|
|
delegate?.handleJobSucceeded(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|