forked from GitHub-Mirror/riotX-android
Download file - WIP
This commit is contained in:
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.cache.CacheService
|
||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.pushers.PushersService
|
||||
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||
@ -46,6 +47,7 @@ interface Session :
|
||||
CacheService,
|
||||
SignOutService,
|
||||
FilterService,
|
||||
FileService,
|
||||
PushRuleService,
|
||||
PushersService {
|
||||
|
||||
|
@ -105,13 +105,6 @@ interface CryptoService {
|
||||
|
||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>)
|
||||
|
||||
/**
|
||||
* Decrypt a file.
|
||||
* Result will be a decrypted file, stored in the cache folder. id parameter will be used to create a sub folder to avoid name collision.
|
||||
* You can pass the eventId
|
||||
*/
|
||||
fun decryptFile(id: String, filename: String, url: String, elementToDecrypt: ElementToDecrypt, callback: MatrixCallback<File>)
|
||||
|
||||
fun getEncryptionAlgorithm(roomId: String): String?
|
||||
|
||||
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.file
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
|
||||
import java.io.File
|
||||
|
||||
|
||||
/**
|
||||
* This interface defines methods to get files.
|
||||
*/
|
||||
interface FileService {
|
||||
|
||||
enum class DownloadMode {
|
||||
/**
|
||||
* Download file in external storage
|
||||
*/
|
||||
TO_EXPORT,
|
||||
/**
|
||||
* Download file in cache
|
||||
*/
|
||||
FOR_INTERNAL_USE
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file.
|
||||
* Result will be a decrypted file, stored in the cache folder. id parameter will be used to create a sub folder to avoid name collision.
|
||||
* You can pass the eventId
|
||||
*/
|
||||
fun downloadFile(
|
||||
downloadMode: DownloadMode,
|
||||
id: String,
|
||||
fileName: String,
|
||||
url: String?,
|
||||
elementToDecrypt: ElementToDecrypt?,
|
||||
callback: MatrixCallback<File>)
|
||||
}
|
@ -114,8 +114,6 @@ internal class CryptoManager @Inject constructor(
|
||||
private val keysBackup: KeysBackup,
|
||||
//
|
||||
private val objectSigner: ObjectSigner,
|
||||
// File decryptor
|
||||
private val fileDecryptor: FileDecryptor,
|
||||
//
|
||||
private val oneTimeKeysUploader: OneTimeKeysUploader,
|
||||
//
|
||||
@ -611,10 +609,6 @@ internal class CryptoManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun decryptFile(id: String, filename: String, url: String, elementToDecrypt: ElementToDecrypt, callback: MatrixCallback<File>) {
|
||||
fileDecryptor.decryptFile(id, filename, url, elementToDecrypt, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt an event
|
||||
*
|
||||
|
@ -14,17 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.crypto
|
||||
package im.vector.matrix.android.internal.session
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
|
||||
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
|
||||
import im.vector.matrix.android.internal.extensions.foldToCallback
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.util.md5
|
||||
import im.vector.matrix.android.internal.util.writeToFile
|
||||
@ -38,33 +39,29 @@ import java.io.File
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class FileDecryptor @Inject constructor(private val context: Context,
|
||||
private val sessionParams: SessionParams,
|
||||
private val contentUrlResolver: ContentUrlResolver,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
||||
internal class DefaultFileService @Inject constructor(private val context: Context,
|
||||
private val sessionParams: SessionParams,
|
||||
private val contentUrlResolver: ContentUrlResolver,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) : FileService {
|
||||
|
||||
val okHttpClient = OkHttpClient()
|
||||
|
||||
fun decryptFile(id: String,
|
||||
fileName: String,
|
||||
url: String,
|
||||
elementToDecrypt: ElementToDecrypt,
|
||||
callback: MatrixCallback<File>) {
|
||||
/**
|
||||
* Download file in the cache folder, and eventually decrypt it
|
||||
* TODO implement clear file, to delete "MF"
|
||||
*/
|
||||
override fun downloadFile(downloadMode: FileService.DownloadMode,
|
||||
id: String,
|
||||
fileName: String,
|
||||
url: String?,
|
||||
elementToDecrypt: ElementToDecrypt?,
|
||||
callback: MatrixCallback<File>) {
|
||||
GlobalScope.launch(coroutineDispatchers.main) {
|
||||
withContext(coroutineDispatchers.io) {
|
||||
Try {
|
||||
// Create dir tree:
|
||||
// <cache>/DF/<md5(userId)>/<md5(id)>/
|
||||
val tmpFolderRoot = File(context.cacheDir, "DF")
|
||||
val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5())
|
||||
val tmpFolder = File(tmpFolderUser, id.md5())
|
||||
val folder = getFolder(downloadMode, id)
|
||||
|
||||
if (!tmpFolder.exists()) {
|
||||
tmpFolder.mkdirs()
|
||||
}
|
||||
|
||||
File(tmpFolder, fileName)
|
||||
File(folder, fileName)
|
||||
}.map { destFile ->
|
||||
if (!destFile.exists()) {
|
||||
Try {
|
||||
@ -79,11 +76,16 @@ internal class FileDecryptor @Inject constructor(private val context: Context,
|
||||
val response = okHttpClient.newCall(request).execute()
|
||||
val inputStream = response.body()?.byteStream()
|
||||
Timber.v("Response size ${response.body()?.contentLength()} - Stream available: ${inputStream?.available()}")
|
||||
if (!response.isSuccessful) {
|
||||
if (!response.isSuccessful
|
||||
|| inputStream == null) {
|
||||
throw IOException()
|
||||
}
|
||||
|
||||
MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) ?: throw IllegalStateException("Decryption error")
|
||||
if (elementToDecrypt != null) {
|
||||
MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) ?: throw IllegalStateException("Decryption error")
|
||||
} else {
|
||||
inputStream
|
||||
}
|
||||
}
|
||||
.map { inputStream ->
|
||||
writeToFile(inputStream, destFile)
|
||||
@ -96,4 +98,24 @@ internal class FileDecryptor @Inject constructor(private val context: Context,
|
||||
.foldToCallback(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFolder(downloadMode: FileService.DownloadMode, id: String): File {
|
||||
return when (downloadMode) {
|
||||
FileService.DownloadMode.FOR_INTERNAL_USE -> {
|
||||
// Create dir tree (MF stands for Matrix File):
|
||||
// <cache>/MF/<md5(userId)>/<md5(id)>/
|
||||
val tmpFolderRoot = File(context.cacheDir, "MF")
|
||||
val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5())
|
||||
File(tmpFolderUser, id.md5())
|
||||
}
|
||||
FileService.DownloadMode.TO_EXPORT -> {
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
}
|
||||
}
|
||||
.also { folder ->
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@ import android.os.Looper
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
@ -30,6 +29,7 @@ import im.vector.matrix.android.api.session.cache.CacheService
|
||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.pushers.PushersService
|
||||
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||
@ -61,20 +61,22 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
private val pushRuleService: PushRuleService,
|
||||
private val pushersService: PushersService,
|
||||
private val cryptoService: CryptoManager,
|
||||
private val fileService: FileService,
|
||||
private val syncThread: SyncThread,
|
||||
private val contentUrlResolver: ContentUrlResolver,
|
||||
private val contentUploadProgressTracker: ContentUploadStateTracker)
|
||||
: Session,
|
||||
RoomService by roomService,
|
||||
RoomDirectoryService by roomDirectoryService,
|
||||
GroupService by groupService,
|
||||
UserService by userService,
|
||||
CryptoService by cryptoService,
|
||||
CacheService by cacheService,
|
||||
SignOutService by signOutService,
|
||||
FilterService by filterService,
|
||||
PushRuleService by pushRuleService,
|
||||
PushersService by pushersService {
|
||||
RoomService by roomService,
|
||||
RoomDirectoryService by roomDirectoryService,
|
||||
GroupService by groupService,
|
||||
UserService by userService,
|
||||
CryptoService by cryptoService,
|
||||
CacheService by cacheService,
|
||||
SignOutService by signOutService,
|
||||
FilterService by filterService,
|
||||
FileService by fileService,
|
||||
PushRuleService by pushRuleService,
|
||||
PushersService by pushersService {
|
||||
|
||||
private var isOpen = false
|
||||
|
||||
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.members.MembershipService
|
||||
@ -27,6 +28,7 @@ import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.session.room.send.SendService
|
||||
import im.vector.matrix.android.api.session.room.state.StateService
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.internal.session.DefaultFileService
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
|
||||
import im.vector.matrix.android.internal.session.room.create.DefaultCreateRoomTask
|
||||
@ -138,4 +140,6 @@ internal abstract class RoomModule {
|
||||
@Binds
|
||||
abstract fun bindTimelineService(timelineService: DefaultTimelineService): TimelineService
|
||||
|
||||
@Binds
|
||||
abstract fun bindFileService(fileService: DefaultFileService): FileService
|
||||
}
|
||||
|
Reference in New Issue
Block a user