diff --git a/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MediaRepository.kt b/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MediaRepository.kt index 253556f86a..3ef5c3af6f 100644 --- a/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MediaRepository.kt +++ b/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MediaRepository.kt @@ -29,7 +29,7 @@ class MediaRepository @Inject constructor( private val pathUtil: PathUtil, ) { companion object { - private const val TAG = "PackageRepository" + private val TAG = this::class.java.simpleName } private fun log(onMsg: () -> String): String = run { diff --git a/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MessagesRepository.kt b/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MessagesRepository.kt new file mode 100644 index 0000000000..b3d80a1540 --- /dev/null +++ b/source/core/data/src/main/kotlin/com/xayah/core/data/repository/MessagesRepository.kt @@ -0,0 +1,50 @@ +package com.xayah.core.data.repository + +import android.content.Context +import com.xayah.core.database.dao.MessageDao +import com.xayah.core.model.CompressionType +import com.xayah.core.model.OpType +import com.xayah.core.model.database.MediaEntity +import com.xayah.core.model.database.MessageEntity +import com.xayah.core.rootservice.service.RemoteRootService +import com.xayah.core.util.LogUtil +import com.xayah.core.util.PathUtil +import com.xayah.core.util.localBackupSaveDir +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.distinctUntilChanged +import javax.inject.Inject + +class MessagesRepository @Inject constructor( + @ApplicationContext private val context: Context, + private val rootService: RemoteRootService, + private val cloudRepository: CloudRepository, + private val messageDao: MessageDao, + private val pathUtil: PathUtil, +) { + companion object { + private val TAG = this::class.java.simpleName + } + + private fun log(onMsg: () -> String): String = run { + val msg = onMsg() + LogUtil.log { TAG to msg } + msg + } + + fun queryFlow(opType: OpType) = messageDao.queryFlow(opType).distinctUntilChanged() + suspend fun query(opType: OpType) = messageDao.query(opType) + suspend fun upsert(item: MessageEntity) = messageDao.upsert(item) + suspend fun upsert(items: List) = messageDao.upsert(items) + suspend fun delete(id: Long) = messageDao.delete(id) + suspend fun queryActivated(opType: OpType) = messageDao.queryActivated(opType) + suspend fun queryActivated(opType: OpType, cloud: String, backupDir: String) = messageDao.queryActivated(opType, cloud, backupDir) + suspend fun query(opType: OpType, preserveId: Long, name: String, cloud: String, backupDir: String) = messageDao.query(opType, preserveId, name, cloud, backupDir) + suspend fun query(opType: OpType, preserveId: Long, name: String, ct: CompressionType, cloud: String, backupDir: String) = messageDao.query(opType, preserveId, name, ct, cloud, backupDir) + suspend fun query(opType: OpType, name: String, cloud: String, backupDir: String) = messageDao.query(opType, name, cloud, backupDir) + suspend fun query(opType: OpType, preserveId: Long, cloud: String, backupDir: String) = messageDao.query(opType, preserveId, cloud, backupDir) + suspend fun query(opType: OpType, cloud: String, backupDir: String) = messageDao.query(opType, cloud, backupDir) + suspend fun query(name: String, opType: OpType) = messageDao.query(name, opType) + + private val localBackupSaveDir get() = context.localBackupSaveDir() + val backupMessagesDir get() = pathUtil.getLocalMessagesDir() +} \ No newline at end of file diff --git a/source/core/database/src/main/kotlin/com/xayah/core/database/dao/MessageDao.kt b/source/core/database/src/main/kotlin/com/xayah/core/database/dao/MessageDao.kt new file mode 100644 index 0000000000..41788c056d --- /dev/null +++ b/source/core/database/src/main/kotlin/com/xayah/core/database/dao/MessageDao.kt @@ -0,0 +1,111 @@ +package com.xayah.core.database.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Query +import androidx.room.Update +import androidx.room.Upsert +import com.xayah.core.model.CompressionType +import com.xayah.core.model.OpType +import com.xayah.core.model.database.MessageEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface MessageDao { + @Upsert(entity = MessageEntity::class) + suspend fun upsert(items: List) + + @Upsert(entity = MessageEntity::class) + suspend fun upsert(item: MessageEntity) + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_opType = :opType" + ) + suspend fun query(opType: OpType): List + + @Query( + "SELECT * FROM MessageEntity" + + " WHERE indexInfo_opType = :opType AND indexInfo_preserveId = :preserveId" + + " AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + ) + suspend fun query(opType: OpType, preserveId: Long, cloud: String, backupDir: String): List + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_opType = :opType AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + ) + suspend fun query(opType: OpType, cloud: String, backupDir: String): List + + @Query( + "SELECT * FROM MessageEntity" + + " WHERE indexInfo_opType = :opType AND indexInfo_name = :name" + + " AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + ) + suspend fun query(opType: OpType, name: String, cloud: String, backupDir: String): List + + @Query( + "SELECT * FROM MessageEntity" + + " WHERE indexInfo_opType = :opType AND indexInfo_preserveId = :preserveId AND indexInfo_name = :name" + + " AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + + " LIMIT 1" + ) + suspend fun query(opType: OpType, preserveId: Long, name: String, cloud: String, backupDir: String): MessageEntity? + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_name = :name AND indexInfo_opType = :opType" + + " LIMIT 1" + ) + suspend fun query(name: String, opType: OpType): MessageEntity? + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_opType = :opType AND indexInfo_preserveId = :preserveId AND indexInfo_name = :name AND indexInfo_compressionType = :ct" + + " AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + + " LIMIT 1" + ) + suspend fun query(opType: OpType, preserveId: Long, name: String, ct: CompressionType, cloud: String, backupDir: String): MessageEntity? + + @Query("SELECT * FROM MessageEntity WHERE indexInfo_opType = :opType") + suspend fun queryActivated(opType: OpType): List + + @Query("SELECT * FROM MessageEntity WHERE indexInfo_opType = :opType AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir") + suspend fun queryActivated(opType: OpType, cloud: String, backupDir: String): List + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_opType = :opType" + ) + fun queryFlow(opType: OpType): Flow> + + @Query( + "SELECT * FROM MessageEntity WHERE" + + " indexInfo_opType = :opType AND indexInfo_cloud = :cloud AND indexInfo_backupDir = :backupDir" + ) + fun queryFlow(opType: OpType, cloud: String, backupDir: String): Flow> + + @Query("SELECT * FROM MessageEntity WHERE indexInfo_opType = :opType AND indexInfo_preserveId = :preserveId") + fun queryFlow(opType: OpType, preserveId: Long): Flow> + + @Query("SELECT * FROM MessageEntity WHERE indexInfo_name = :name AND indexInfo_opType = :opType AND indexInfo_preserveId = :preserveId LIMIT 1") + fun queryFlow(name: String, opType: OpType, preserveId: Long): Flow + + @Query("SELECT * FROM MessageEntity WHERE indexInfo_name = :name AND indexInfo_opType = :opType") + fun queryFlow(name: String, opType: OpType): Flow> + + @Query("SELECT COUNT(*) FROM MessageEntity") + suspend fun count(): Long + + @Delete(entity = MessageEntity::class) + suspend fun delete(item: MessageEntity) + + @Query("DELETE FROM MessageEntity WHERE id = :id") + suspend fun delete(id: Long) + + @Query("DELETE FROM MessageEntity WHERE id in (:ids)") + suspend fun delete(ids: List) + + @Update(MessageEntity::class) + suspend fun update(item: MessageEntity) +} \ No newline at end of file diff --git a/source/core/database/src/main/kotlin/com/xayah/core/database/dao/TaskDao.kt b/source/core/database/src/main/kotlin/com/xayah/core/database/dao/TaskDao.kt index 6b0296782d..03bdcf65f5 100644 --- a/source/core/database/src/main/kotlin/com/xayah/core/database/dao/TaskDao.kt +++ b/source/core/database/src/main/kotlin/com/xayah/core/database/dao/TaskDao.kt @@ -4,8 +4,10 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.Upsert import com.xayah.core.model.ProcessingType +import com.xayah.core.model.database.MessageEntity import com.xayah.core.model.database.ProcessingInfoEntity import com.xayah.core.model.database.TaskDetailMediaEntity +import com.xayah.core.model.database.TaskDetailMessageEntity import com.xayah.core.model.database.TaskDetailPackageEntity import com.xayah.core.model.database.TaskEntity import kotlinx.coroutines.flow.Flow @@ -21,9 +23,15 @@ interface TaskDao { @Upsert(entity = TaskDetailMediaEntity::class) suspend fun upsert(item: TaskDetailMediaEntity): Long + @Upsert(entity = TaskDetailMessageEntity::class) + suspend fun upsert(item: TaskDetailMessageEntity): Long + @Upsert(entity = ProcessingInfoEntity::class) suspend fun upsert(item: ProcessingInfoEntity): Long + @Upsert(entity = MessageEntity::class) + suspend fun upsert(item: MessageEntity): Long + @Query("SELECT * FROM TaskEntity WHERE id = :id LIMIT 1") fun queryTaskFlow(id: Long): Flow diff --git a/source/core/model/src/main/kotlin/com/xayah/core/model/Enum.kt b/source/core/model/src/main/kotlin/com/xayah/core/model/Enum.kt index 6898d49f0e..491eece3c6 100644 --- a/source/core/model/src/main/kotlin/com/xayah/core/model/Enum.kt +++ b/source/core/model/src/main/kotlin/com/xayah/core/model/Enum.kt @@ -1,6 +1,7 @@ package com.xayah.core.model import android.content.Context +import android.provider.Telephony const val TAR_SUFFIX = "tar" const val ZSTD_SUFFIX = "tar.zst" @@ -37,7 +38,8 @@ enum class OpType { enum class TaskType { PACKAGE, - MEDIA; + MEDIA, + MESSAGE; companion object } @@ -169,4 +171,28 @@ enum class ProcessingInfoType { BACKUP_ITSELF, SAVE_ICONS, SET_UP_INST_ENV, -} \ No newline at end of file +} + +enum class MessageType { + SMS, + MMS, +} + +enum class SMSMessageBox(val type: Int) { + ALL(Telephony.Sms.MESSAGE_TYPE_ALL), + DRAFT(Telephony.Sms.MESSAGE_TYPE_DRAFT), + FAILED(Telephony.Sms.MESSAGE_TYPE_FAILED), + INBOX(Telephony.Sms.MESSAGE_TYPE_INBOX), + OUTBOX(Telephony.Sms.MESSAGE_TYPE_OUTBOX), + QUEUED(Telephony.Sms.MESSAGE_TYPE_QUEUED), + SENT(Telephony.Sms.MESSAGE_TYPE_SENT), +} + +enum class MMSMessageBox(val type: Int) { + ALL(Telephony.Mms.MESSAGE_BOX_ALL), + DRAFTS(Telephony.Mms.MESSAGE_BOX_DRAFTS), + FAILED(Telephony.Mms.MESSAGE_BOX_FAILED), + INBOX(Telephony.Mms.MESSAGE_BOX_INBOX), + OUTBOX(Telephony.Mms.MESSAGE_BOX_OUTBOX), + SENT(Telephony.Mms.MESSAGE_BOX_SENT), +} diff --git a/source/core/model/src/main/kotlin/com/xayah/core/model/database/MessageEntity.kt b/source/core/model/src/main/kotlin/com/xayah/core/model/database/MessageEntity.kt new file mode 100644 index 0000000000..a5597c5735 --- /dev/null +++ b/source/core/model/src/main/kotlin/com/xayah/core/model/database/MessageEntity.kt @@ -0,0 +1,112 @@ +package com.xayah.core.model.database + +import androidx.room.ColumnInfo +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.xayah.core.model.CompressionType +import com.xayah.core.model.MMSMessageBox +import com.xayah.core.model.MessageType +import com.xayah.core.model.OpType +import com.xayah.core.model.SMSMessageBox +import kotlinx.serialization.Serializable + +interface BaseMessageTypeInfo + +@Serializable +data class MessageIndexInfo( + var opType: OpType, + var name: String, + var compressionType: CompressionType, + var preserveId: Long, + var cloud: String, + var backupDir: String, + var messageType: MessageType, +) + +data class MMSTypeInfo( + val id: Long, + val contentClass: Long, + val contentLocation: String, + val contentType: String, + val deliveryReport: Long, + val deliveryTime: Long, + val expiry: Long, + val messageBox: MMSMessageBox, + val messageClass: String, + val messageId: String, + val messageSize: Long, + val messageType: Long, + val mmsVersion: Long, + val priority: Long, + val readReport: Long, + val readStatus: Long, + val reportAllowed: Long, + val responseStatus: Long, + val responseText: String, + val retrieveStatus: Long, + val retrieveText: String, + val retrieveTextCharset: Long, + val subjectCharset: Long, + val textOnly: Long, + val threadId: Long, + val transactionId: String, + + // Mms.Part + val filename: String, +) : BaseMessageTypeInfo + +data class SMSTypeInfo( + val creator: String, + val errorCode: Long, + val person: Long, + val protocol: Long, + val replyPathPresent: Long, + val serviceCenter: String, + val type: SMSMessageBox, +) : BaseMessageTypeInfo + +@Serializable +data class MessageBaseInfo( + val address: String, + val body: String, // SMS: body, MMS: text + val date: Long, + val dateSent: Long, + val locked: Long, + val read: Long, + val seen: Long, + val status: Long, + val subject: String, + val subscriptionId: Long, +) + +@Serializable +data class MessageToggleInfo( + var blocked: Boolean, + var activated: Boolean, + var existed: Boolean, +) + +@Serializable +@Entity +data class MessageEntity( + @PrimaryKey(autoGenerate = true) var id: Long, + @ColumnInfo(defaultValue = "0") var processingIndex: Int = 0, + @Embedded(prefix = "indexInfo_") var indexInfo: MessageIndexInfo, + @Embedded(prefix = "baseInfo_") var messageBaseInfo: MessageBaseInfo, + @Embedded(prefix = "typeInfo_") var messageTypeInfo: BaseMessageTypeInfo, + @Embedded(prefix = "toggleInfo_") var messageToggleInfo: MessageToggleInfo, +) { + fun asString(): String { + return Gson().let { + it.toJson( + mapOf( + Pair("baseInfo", it.toJsonTree(messageBaseInfo)), + Pair("typeInfo", it.toJsonTree(messageTypeInfo)), + ) + ) + } + } +} diff --git a/source/core/model/src/main/kotlin/com/xayah/core/model/database/TaskDetailEntity.kt b/source/core/model/src/main/kotlin/com/xayah/core/model/database/TaskDetailEntity.kt index 469d5ce1bc..e5c5bc2ca3 100644 --- a/source/core/model/src/main/kotlin/com/xayah/core/model/database/TaskDetailEntity.kt +++ b/source/core/model/src/main/kotlin/com/xayah/core/model/database/TaskDetailEntity.kt @@ -57,6 +57,15 @@ data class TaskDetailMediaEntity( } } +@Entity +data class TaskDetailMessageEntity( + @PrimaryKey(autoGenerate = true) var id: Long = 0, + var taskId: Long, + var state: OperationState = OperationState.IDLE, + @ColumnInfo(defaultValue = "0") var processingIndex: Int = 0, + @Embedded(prefix = "messageEntity_") var messageEntity: MessageEntity, +) + @Entity data class ProcessingInfoEntity( @PrimaryKey(autoGenerate = true) var id: Long = 0, diff --git a/source/core/model/src/main/kotlin/com/xayah/core/model/util/ModelUtil.kt b/source/core/model/src/main/kotlin/com/xayah/core/model/util/ModelUtil.kt index 93fb1fbac1..484c0c4309 100644 --- a/source/core/model/src/main/kotlin/com/xayah/core/model/util/ModelUtil.kt +++ b/source/core/model/src/main/kotlin/com/xayah/core/model/util/ModelUtil.kt @@ -15,9 +15,11 @@ import com.xayah.core.model.ThemeType import com.xayah.core.model.ZSTD_SUFFIX import com.xayah.core.model.database.Info import com.xayah.core.model.database.MediaEntity +import com.xayah.core.model.database.MessageEntity import com.xayah.core.model.database.PackageEntity import com.xayah.core.model.database.ProcessingInfoEntity import com.xayah.core.model.database.TaskDetailMediaEntity +import com.xayah.core.model.database.TaskDetailMessageEntity import com.xayah.core.model.database.TaskDetailPackageEntity import com.xayah.core.model.database.TaskEntity import java.text.DecimalFormat @@ -108,6 +110,16 @@ fun TaskDetailPackageEntity.set( if (packageEntity != null) this.packageEntity = packageEntity } +fun TaskDetailMessageEntity.set( + state: OperationState? = null, + processingIndex: Int? = null, + messageEntity: MessageEntity? = null, +) = run { + if (state != null) this.state = state + if (processingIndex != null) this.processingIndex = processingIndex + if (messageEntity != null) this.messageEntity = messageEntity +} + fun TaskDetailPackageEntity.set( dataType: DataType, bytes: Long? = null, diff --git a/source/core/service/src/main/kotlin/com/xayah/core/service/messages/AbstractMessagesService.kt b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/AbstractMessagesService.kt new file mode 100644 index 0000000000..d3f3dd02f9 --- /dev/null +++ b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/AbstractMessagesService.kt @@ -0,0 +1,27 @@ +package com.xayah.core.service.messages + +import com.xayah.core.data.repository.MessagesRepository +import com.xayah.core.database.dao.MessageDao +import com.xayah.core.model.OperationState +import com.xayah.core.model.database.MessageEntity +import com.xayah.core.model.database.TaskDetailMessageEntity +import com.xayah.core.model.util.set +import com.xayah.core.service.AbstractProcessingService + +internal abstract class AbstractMessagesService : AbstractProcessingService() { + protected val mMessageEntities: MutableList = mutableListOf() + + protected suspend fun TaskDetailMessageEntity.update( + state: OperationState? = null, + processingIndex: Int? = null, + messageEntity: MessageEntity? = null, + ) = run { + set(state, processingIndex, messageEntity) + mTaskDao.upsert(this) + } + + protected abstract val mMessageDao: MessageDao + protected abstract val mMessagesRepo: MessagesRepository + protected abstract val mRootDir: String + protected abstract val mMessagesDir: String +} \ No newline at end of file diff --git a/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/AbstractBackupService.kt b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/AbstractBackupService.kt new file mode 100644 index 0000000000..1610b4d5af --- /dev/null +++ b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/AbstractBackupService.kt @@ -0,0 +1,96 @@ +package com.xayah.core.service.messages.backup + +import com.xayah.core.model.DataType +import com.xayah.core.model.OpType +import com.xayah.core.model.OperationState +import com.xayah.core.model.ProcessingInfoType +import com.xayah.core.model.ProcessingType +import com.xayah.core.model.TaskType +import com.xayah.core.model.database.Info +import com.xayah.core.model.database.ProcessingInfoEntity +import com.xayah.core.model.database.TaskDetailMediaEntity +import com.xayah.core.model.database.TaskDetailMessageEntity +import com.xayah.core.service.R +import com.xayah.core.service.messages.AbstractMessagesService +import com.xayah.core.util.NotificationUtil + +internal abstract class AbstractBackupService : AbstractMessagesService() { + override suspend fun onInitializingPreprocessingEntities(entities: MutableList) { + entities.apply { + add(ProcessingInfoEntity( + taskId = mTaskEntity.id, + title = mContext.getString(R.string.necessary_preparations), + type = ProcessingType.PREPROCESSING, + infoType = ProcessingInfoType.NECESSARY_PREPARATIONS + ).apply { + id = mTaskDao.upsert(this) + }) + } + } + + override suspend fun onInitializingPostProcessingEntities(entities: MutableList) { + } + + override suspend fun onInitializing() { + val messages = mMessagesRepo.queryActivated(OpType.BACKUP) + + messages.forEach { message -> + mMessageEntities.add( + TaskDetailMessageEntity( + taskId = mTaskEntity.id, + messageEntity = message, + ).apply { + id = mTaskDao.upsert(this) + }) + } + } + + override suspend fun beforePreprocessing() { + NotificationUtil.notify(mContext, mNotificationBuilder, mContext.getString(R.string.backing_up), mContext.getString(R.string.preprocessing)) + } + + override suspend fun onPreprocessing(entity: ProcessingInfoEntity) { + when (entity.infoType) { + ProcessingInfoType.NECESSARY_PREPARATIONS -> { + log { "Trying to create: $mMessagesDir." } + mRootService.mkdirs(mMessagesDir) + val isSuccess = runCatchingOnService { onTargetDirsCreated() } + entity.update(progress = 1f, state = if (isSuccess) OperationState.DONE else OperationState.ERROR) + } + + else -> {} + } + } + + override suspend fun onProcessing() { + mTaskEntity.update(rawBytes = mTaskRepo.getRawBytes(TaskType.MESSAGE), availableBytes = mTaskRepo.getAvailableBytes(OpType.BACKUP), totalBytes = mTaskRepo.getTotalBytes(OpType.BACKUP), totalCount = mMessageEntities.size) + log { "Task count: ${mMessageEntities.size}." } + + mMessageEntities.forEachIndexed { index, message -> + executeAtLeast { + val p = message.messageEntity.messageBaseInfo.address + + NotificationUtil.notify( + mContext, + mNotificationBuilder, + mContext.getString(R.string.backing_up), + p, + mMessageEntities.size, + index + ) + log { "Current message: $p" } + + message.update(state = OperationState.PROCESSING) + + val jsonString = message.messageEntity.asString() + } + mTaskEntity.update(processingIndex = mTaskEntity.processingIndex + 1) + } + } + + override suspend fun onPostProcessing(entity: ProcessingInfoEntity) { + + } + + protected open suspend fun onTargetDirsCreated() {} +} \ No newline at end of file diff --git a/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/BackupServiceCloudImpl.kt b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/BackupServiceCloudImpl.kt new file mode 100644 index 0000000000..33d165f7f2 --- /dev/null +++ b/source/core/service/src/main/kotlin/com/xayah/core/service/messages/backup/BackupServiceCloudImpl.kt @@ -0,0 +1,83 @@ +package com.xayah.core.service.messages.backup + +import com.xayah.core.data.repository.CloudRepository +import com.xayah.core.data.repository.MediaRepository +import com.xayah.core.data.repository.MessagesRepository +import com.xayah.core.data.repository.TaskRepository +import com.xayah.core.database.dao.MediaDao +import com.xayah.core.database.dao.MessageDao +import com.xayah.core.database.dao.TaskDao +import com.xayah.core.model.OpType +import com.xayah.core.model.TaskType +import com.xayah.core.model.database.CloudEntity +import com.xayah.core.model.database.ProcessingInfoEntity +import com.xayah.core.model.database.TaskEntity +import com.xayah.core.network.client.CloudClient +import com.xayah.core.rootservice.service.RemoteRootService +import com.xayah.core.service.util.CommonBackupUtil +import com.xayah.core.util.PathUtil +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +internal class BackupServiceCloudImpl @Inject constructor() : AbstractBackupService() { + override val mTAG: String = "BackupServiceCloudImpl" + + @Inject + override lateinit var mRootService: RemoteRootService + + @Inject + override lateinit var mPathUtil: PathUtil + + @Inject + override lateinit var mCommonBackupUtil: CommonBackupUtil + + @Inject + override lateinit var mTaskDao: TaskDao + + @Inject + override lateinit var mTaskRepo: TaskRepository + + @Inject + override lateinit var mMessagesRepo: MessagesRepository + + override val mTaskEntity by lazy { + TaskEntity( + id = 0, + opType = OpType.BACKUP, + taskType = TaskType.MESSAGE, + startTimestamp = mStartTimestamp, + endTimestamp = mEndTimestamp, + backupDir = mRootDir, + isProcessing = true, + ) + } + + override suspend fun onTargetDirsCreated() { + mCloudRepo.getClient().also { (c, e) -> + mCloudEntity = e + mClient = c + } + + mRemotePath = mCloudEntity.remote + mRemoteMessagesDir = mPathUtil.getCloudRemoteMessagesDir(mRemotePath) + mTaskEntity.update(cloud = mCloudEntity.name, backupDir = mRemotePath) + + log { "Trying to create: $mRemoteMessagesDir." } + mClient.mkdirRecursively(mRemoteMessagesDir) + } + + @Inject + override lateinit var mMessageDao: MessageDao + + @Inject + lateinit var mCloudRepo: CloudRepository + + override val mRootDir by lazy { mPathUtil.getCloudTmpDir() } + override val mMessagesDir by lazy { mPathUtil.getCloudTmpMessagesDir() } + + private lateinit var mCloudEntity: CloudEntity + private lateinit var mClient: CloudClient + private lateinit var mRemotePath: String + private lateinit var mRemoteMessagesDir: String +} diff --git a/source/core/service/src/main/kotlin/com/xayah/core/service/util/MessagesBackupUtil.kt b/source/core/service/src/main/kotlin/com/xayah/core/service/util/MessagesBackupUtil.kt new file mode 100644 index 0000000000..83648a9a3d --- /dev/null +++ b/source/core/service/src/main/kotlin/com/xayah/core/service/util/MessagesBackupUtil.kt @@ -0,0 +1,22 @@ +package com.xayah.core.service.util + +import android.content.Context +import com.xayah.core.data.repository.CloudRepository +import com.xayah.core.data.repository.MediaRepository +import com.xayah.core.database.dao.TaskDao +import com.xayah.core.rootservice.service.RemoteRootService +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +class MessagesBackupUtil @Inject constructor( + @ApplicationContext val context: Context, + private val rootService: RemoteRootService, + private val taskDao: TaskDao, + private val mediaRepository: MediaRepository, + private val commonBackupUtil: CommonBackupUtil, + private val cloudRepository: CloudRepository, +) { + companion object { + private val TAG = this::class.java.simpleName + } +} \ No newline at end of file diff --git a/source/core/util/src/main/kotlin/com/xayah/core/util/PathUtil.kt b/source/core/util/src/main/kotlin/com/xayah/core/util/PathUtil.kt index da038641b1..8b414073d5 100644 --- a/source/core/util/src/main/kotlin/com/xayah/core/util/PathUtil.kt +++ b/source/core/util/src/main/kotlin/com/xayah/core/util/PathUtil.kt @@ -17,6 +17,7 @@ const val ApksRelativeDir = "apks" const val AppsRelativeDir = "apps" const val FilesRelativeDir = "files" const val ConfigsRelativeDir = "configs" +const val MessagesRelativeDir = "messages" const val ConfigsPackageRestoreName = "package_restore_config.json" const val ConfigsMediaRestoreName = "media_restore_config.json" const val ConfigsConfigurationsName = "configurations.json" @@ -68,6 +69,7 @@ class PathUtil @Inject constructor( fun getAppsRelativeDir(): String = AppsRelativeDir fun getFilesRelativeDir(): String = FilesRelativeDir + fun getMessagesRelativeDir(): String = MessagesRelativeDir fun getPackageRestoreConfigDst(dstDir: String): String = "${dstDir}/$ConfigsPackageRestoreName" @@ -94,12 +96,16 @@ class PathUtil @Inject constructor( private fun getAppsDir(parent: String): String = "${parent}/${getAppsRelativeDir()}" private fun getFilesDir(parent: String): String = "${parent}/${getFilesRelativeDir()}" + private fun getMessagesDir(parent: String): String = "${parent}/${getMessagesRelativeDir()}" fun getLocalBackupAppsDir(): String = getAppsDir(parent = context.localBackupSaveDir()) fun getCloudTmpAppsDir(): String = getAppsDir(parent = context.cloudTmpAbsoluteDir()) fun getCloudRemoteAppsDir(remote: String): String = getAppsDir(parent = remote) fun getLocalBackupFilesDir(): String = getFilesDir(parent = context.localBackupSaveDir()) fun getCloudTmpFilesDir(): String = getFilesDir(parent = context.cloudTmpAbsoluteDir()) fun getCloudRemoteFilesDir(remote: String): String = getFilesDir(parent = remote) + fun getLocalMessagesDir(): String = getMessagesDir(parent = context.localBackupSaveDir()) + fun getCloudTmpMessagesDir(): String = getMessagesDir(parent = context.cloudTmpAbsoluteDir()) + fun getCloudRemoteMessagesDir(remote: String): String = getMessagesDir(parent = remote) fun getTmpApkPath(packageName: String): String = "${context.tmpApksDir()}/$packageName"