Unverified Commit 65ebc5bc authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #1858 from RocketChat/retry-db

[FIX] Try to avoid locked database
parents 27e71c06 6a0c4051
...@@ -37,6 +37,8 @@ import chat.rocket.android.server.infraestructure.state ...@@ -37,6 +37,8 @@ import chat.rocket.android.server.infraestructure.state
import chat.rocket.android.util.extension.getByteArray import chat.rocket.android.util.extension.getByteArray
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.exhaustive
import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
...@@ -901,7 +903,8 @@ class ChatRoomPresenter @Inject constructor( ...@@ -901,7 +903,8 @@ class ChatRoomPresenter @Inject constructor(
// TODO: move this to new interactor or FetchChatRoomsInteractor? // TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomAsync(roomId: String): ChatRoom? = withContext(CommonPool) { private suspend fun getChatRoomAsync(roomId: String): ChatRoom? = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().get(roomId)?.let { retryDB("getRoom($roomId)") {
dbManager.chatRoomDao().get(roomId)?.let {
with(it.chatRoom) { with(it.chatRoom) {
ChatRoom( ChatRoom(
id = id, id = id,
...@@ -934,10 +937,12 @@ class ChatRoomPresenter @Inject constructor( ...@@ -934,10 +937,12 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
} }
}
// TODO: move this to new interactor or FetchChatRoomsInteractor? // TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) { private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().getAllSync().filter { retryDB("getAllSync()") {
dbManager.chatRoomDao().getAllSync().filter {
if (name == null) { if (name == null) {
return@filter true return@filter true
} }
...@@ -975,6 +980,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -975,6 +980,7 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
} }
}
fun joinChat(chatRoomId: String) { fun joinChat(chatRoomId: String) {
launchUI(strategy) { launchUI(strategy) {
......
...@@ -3,9 +3,12 @@ package chat.rocket.android.chatrooms.infrastructure ...@@ -3,9 +3,12 @@ package chat.rocket.android.chatrooms.infrastructure
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import chat.rocket.android.db.ChatRoomDao import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.model.ChatRoom import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.util.retryDB
import javax.inject.Inject import javax.inject.Inject
class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao){ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
// TODO - check how to use retryDB here - suspend
fun getChatRooms(order: Order): LiveData<List<ChatRoom>> { fun getChatRooms(order: Order): LiveData<List<ChatRoom>> {
return when(order) { return when(order) {
Order.ACTIVITY -> dao.getAll() Order.ACTIVITY -> dao.getAll()
...@@ -15,9 +18,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao){ ...@@ -15,9 +18,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao){
} }
} }
fun search(query: String) = dao.searchSync(query) suspend fun search(query: String) =
retryDB("roomSearch($query)") { dao.searchSync(query) }
fun count() = dao.count() suspend fun count() = retryDB("roomsCount") { dao.count() }
enum class Order { enum class Order {
ACTIVITY, ACTIVITY,
......
...@@ -13,6 +13,7 @@ import chat.rocket.android.server.domain.useRealName ...@@ -13,6 +13,7 @@ import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infraestructure.ConnectionManager
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
...@@ -41,11 +42,31 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -41,11 +42,31 @@ class ChatRoomsPresenter @Inject constructor(
private val client = manager.client private val client = manager.client
private val settings = settingsRepository.get(currentServer) private val settings = settingsRepository.get(currentServer)
fun loadChatRoom(roomId: String) {
launchUI(strategy) {
view.showLoadingRoom("")
try {
val room = dbManager.getRoom(roomId)
if (room != null) {
loadChatRoom(room.chatRoom, true)
} else {
Timber.d("Error loading channel")
view.showGenericErrorMessage()
}
} catch (ex: Exception) {
Timber.d(ex, "Error loading channel")
view.showGenericErrorMessage()
} finally {
view.hideLoadingRoom()
}
}
}
fun loadChatRoom(chatRoom: RoomUiModel) { fun loadChatRoom(chatRoom: RoomUiModel) {
launchUI(strategy) { launchUI(strategy) {
view.showLoadingRoom(chatRoom.name) view.showLoadingRoom(chatRoom.name)
try { try {
val room = dbManager.getRoom(chatRoom.id) val room = retryDB("getRoom(${chatRoom.id}") { dbManager.getRoom(chatRoom.id) }
if (room != null) { if (room != null) {
loadChatRoom(room.chatRoom, true) loadChatRoom(room.chatRoom, true)
} else { } else {
......
...@@ -84,8 +84,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -84,8 +84,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
if (bundle != null) { if (bundle != null) {
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
chatRoomId?.let { chatRoomId?.let {
// TODO - bring back support to load a room from id. presenter.loadChatRoom(it)
//presenter.goToChatRoomWithId(it)
chatRoomId = null chatRoomId = null
} }
} }
......
...@@ -19,6 +19,7 @@ import chat.rocket.android.util.extensions.exhaustive ...@@ -19,6 +19,7 @@ import chat.rocket.android.util.extensions.exhaustive
import chat.rocket.android.util.extensions.removeTrailingSlash import chat.rocket.android.util.extensions.removeTrailingSlash
import chat.rocket.android.util.extensions.toEntity import chat.rocket.android.util.extensions.toEntity
import chat.rocket.android.util.extensions.userId import chat.rocket.android.util.extensions.userId
import chat.rocket.android.util.retryDB
import chat.rocket.common.model.BaseRoom import chat.rocket.common.model.BaseRoom
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
...@@ -91,13 +92,15 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -91,13 +92,15 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
} }
} }
fun logout() { suspend fun logout() {
database.clearAllTables() retryDB("clearAllTables") { database.clearAllTables() }
} }
suspend fun getRoom(id: String) = withContext(dbManagerContext) { suspend fun getRoom(id: String) = withContext(dbManagerContext) {
retryDB("getRoom($id)") {
chatRoomDao().get(id) chatRoomDao().get(id)
} }
}
fun processUsersBatch(users: List<User>) { fun processUsersBatch(users: List<User>) {
launch(dbManagerContext) { launch(dbManagerContext) {
...@@ -151,7 +154,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -151,7 +154,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
fun updateSelfUser(myself: Myself) { fun updateSelfUser(myself: Myself) {
launch(dbManagerContext) { launch(dbManagerContext) {
val user = userDao().getUser(myself.id) val user = retryDB("getUser(${myself.id})") { userDao().getUser(myself.id) }
val entity = user?.copy( val entity = user?.copy(
name = myself.name ?: user.name, name = myself.name ?: user.name,
username = myself.username ?: user.username, username = myself.username ?: user.username,
...@@ -335,7 +338,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -335,7 +338,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
} }
private suspend fun updateRoom(data: Room): ChatRoomEntity? { private suspend fun updateRoom(data: Room): ChatRoomEntity? {
return chatRoomDao().get(data.id)?.let { current -> return retryDB("getChatRoom(${data.id})") { chatRoomDao().get(data.id) }?.let { current ->
with(data) { with(data) {
val chatRoom = current.chatRoom val chatRoom = current.chatRoom
...@@ -373,7 +376,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -373,7 +376,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
context.getString(R.string.msg_sent_attachment) context.getString(R.string.msg_sent_attachment)
private suspend fun updateSubscription(data: Subscription): ChatRoomEntity? { private suspend fun updateSubscription(data: Subscription): ChatRoomEntity? {
return chatRoomDao().get(data.roomId)?.let { current -> return retryDB("getRoom(${data.roomId}") { chatRoomDao().get(data.roomId) }?.let { current ->
with(data) { with(data) {
val userId = if (type is RoomType.DirectMessage) { val userId = if (type is RoomType.DirectMessage) {
...@@ -539,9 +542,11 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -539,9 +542,11 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
} }
} }
private fun findUser(userId: String): String? = userDao().findUser(userId) private suspend fun findUser(userId: String): String? =
retryDB("findUser($userId)") { userDao().findUser(userId) }
private fun doOperation(operation: Operation) { private suspend fun doOperation(operation: Operation) {
retryDB(description = "doOperation($operation)") {
when (operation) { when (operation) {
is Operation.ClearStatus -> userDao().clearStatus() is Operation.ClearStatus -> userDao().clearStatus()
is Operation.UpdateRooms -> { is Operation.UpdateRooms -> {
...@@ -573,6 +578,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -573,6 +578,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
} }
}.exhaustive }.exhaustive
} }
}
} }
sealed class Operation { sealed class Operation {
......
...@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
......
...@@ -7,6 +7,7 @@ import chat.rocket.android.files.uimodel.FileUiModel ...@@ -7,6 +7,7 @@ import chat.rocket.android.files.uimodel.FileUiModel
import chat.rocket.android.files.uimodel.FileUiModelMapper import chat.rocket.android.files.uimodel.FileUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
......
...@@ -6,6 +6,7 @@ import chat.rocket.android.members.uimodel.MemberUiModel ...@@ -6,6 +6,7 @@ import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.members.uimodel.MemberUiModelMapper import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
......
...@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -5,6 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
......
...@@ -296,11 +296,8 @@ class PushManager @Inject constructor( ...@@ -296,11 +296,8 @@ class PushManager @Inject constructor(
} }
private fun getContentIntent(context: Context, notificationId: Int, pushMessage: PushMessage, grouped: Boolean = false): PendingIntent { private fun getContentIntent(context: Context, notificationId: Int, pushMessage: PushMessage, grouped: Boolean = false): PendingIntent {
val notificationIntent = context.changeServerIntent(pushMessage.info.host, chatRoomId = pushMessage.info.roomId) val roomId = if (!grouped) pushMessage.info.roomId else null
// TODO - add support to go directly to the chatroom val notificationIntent = context.changeServerIntent(pushMessage.info.host, chatRoomId = roomId)
/*if (!isGrouped) {
notificationIntent.putExtra(EXTRA_ROOM_ID, pushMessage.info.roomId)
}*/
return PendingIntent.getActivity(context, random.nextInt(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, random.nextInt(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
......
...@@ -7,6 +7,7 @@ import chat.rocket.android.db.model.FullMessage ...@@ -7,6 +7,7 @@ import chat.rocket.android.db.model.FullMessage
import chat.rocket.android.db.model.ReactionEntity import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.UrlEntity import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.util.retryDB
import chat.rocket.common.model.SimpleRoom import chat.rocket.common.model.SimpleRoom
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
...@@ -135,14 +136,18 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) { ...@@ -135,14 +136,18 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
with(attachment) { with(attachment) {
val fields = if (hasFields) { val fields = if (hasFields) {
withContext(CommonPool) { withContext(CommonPool) {
retryDB("getAttachmentFields(${attachment._id})") {
dbManager.messageDao().getAttachmentFields(attachment._id) dbManager.messageDao().getAttachmentFields(attachment._id)
}
}.map { Field(it.title, it.value) } }.map { Field(it.title, it.value) }
} else { } else {
null null
} }
val actions = if (hasActions) { val actions = if (hasActions) {
withContext(CommonPool) { withContext(CommonPool) {
retryDB("getAttachmentActions(${attachment._id})") {
dbManager.messageDao().getAttachmentActions(attachment._id) dbManager.messageDao().getAttachmentActions(attachment._id)
}
}.mapNotNull { mapAction(it) } }.mapNotNull { mapAction(it) }
} else { } else {
null null
...@@ -183,29 +188,6 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) { ...@@ -183,29 +188,6 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
return list return list
} }
/*private suspend fun mapColorAttachmentWithFields(entity: AttachmentEntity): ColorAttachment {
val fields = withContext(CommonPool) {
dbManager.messageDao().getAttachmentFields(entity._id)
}.map { Field(it.title, it.value) }
return with(entity) {
ColorAttachment(
color = Color.Custom(color ?: DEFAULT_COLOR_STR),
text = text ?: "",
fallback = fallback,
fields = fields)
}
}
private suspend fun mapActionAttachment(attachment: AttachmentEntity): ActionsAttachment {
val actions = withContext(CommonPool) {
dbManager.messageDao().getAttachmentActions(attachment._id)
}.mapNotNull { mapAction(it) }
return with(attachment) {
// TODO - remove the default "vertical" value from here...
ActionsAttachment(title, actions, buttonAlignment ?: "vertical")
}
}*/
private fun mapAction(action: AttachmentActionEntity): Action? { private fun mapAction(action: AttachmentActionEntity): Action? {
return when (action.type) { return when (action.type) {
"button" -> ButtonAction(action.type, action.text, action.url, action.isWebView, "button" -> ButtonAction(action.type, action.text, action.url, action.isWebView,
...@@ -214,13 +196,4 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) { ...@@ -214,13 +196,4 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
else -> null else -> null
} }
} }
/*private suspend fun mapAuthorAttachment(attachment: AttachmentEntity): AuthorAttachment {
val fields = withContext(CommonPool) {
dbManager.messageDao().getAttachmentFields(attachment._id)
}.map { Field(it.title, it.value) }
return with(attachment) {
AuthorAttachment(authorLink!!, authorIcon, authorName, fields)
}
}*/
} }
\ No newline at end of file
...@@ -4,6 +4,7 @@ import chat.rocket.android.db.DatabaseManager ...@@ -4,6 +4,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.Operation import chat.rocket.android.db.Operation
import chat.rocket.android.db.model.MessagesSync import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.server.domain.MessagesRepository import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.util.retryDB
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
...@@ -14,26 +15,32 @@ class DatabaseMessagesRepository( ...@@ -14,26 +15,32 @@ class DatabaseMessagesRepository(
) : MessagesRepository { ) : MessagesRepository {
override suspend fun getById(id: String): Message? = withContext(CommonPool) { override suspend fun getById(id: String): Message? = withContext(CommonPool) {
retryDB("getMessageById($id)") {
dbManager.messageDao().getMessageById(id)?.let { message -> mapper.map(message) } dbManager.messageDao().getMessageById(id)?.let { message -> mapper.map(message) }
} }
}
override suspend fun getByRoomId(roomId: String): List<Message> = withContext(CommonPool) { override suspend fun getByRoomId(roomId: String): List<Message> = withContext(CommonPool) {
// FIXME - investigate how to avoid this distinctBy here, since DAO is returning a lot of // FIXME - investigate how to avoid this distinctBy here, since DAO is returning a lot of
// duplicate rows (something related to our JOINS and relations on Room) // duplicate rows (something related to our JOINS and relations on Room)
retryDB("getMessagesByRoomId($roomId)") {
dbManager.messageDao().getMessagesByRoomId(roomId) dbManager.messageDao().getMessagesByRoomId(roomId)
.distinctBy { it.message.message.id } .distinctBy { it.message.message.id }
.let { messages -> .let { messages ->
mapper.map(messages) mapper.map(messages)
} }
} }
}
override suspend fun getRecentMessages(roomId: String, count: Long): List<Message> = withContext(CommonPool) { override suspend fun getRecentMessages(roomId: String, count: Long): List<Message> = withContext(CommonPool) {
retryDB("getRecentMessagesByRoomId($roomId, $count)") {
dbManager.messageDao().getRecentMessagesByRoomId(roomId, count) dbManager.messageDao().getRecentMessagesByRoomId(roomId, count)
.distinctBy { it.message.message.id } .distinctBy { it.message.message.id }
.let { messages -> .let { messages ->
mapper.map(messages) mapper.map(messages)
} }
} }
}
override suspend fun save(message: Message) { override suspend fun save(message: Message) {
dbManager.processMessagesBatch(listOf(message)).join() dbManager.processMessagesBatch(listOf(message)).join()
...@@ -45,27 +52,33 @@ class DatabaseMessagesRepository( ...@@ -45,27 +52,33 @@ class DatabaseMessagesRepository(
override suspend fun removeById(id: String) { override suspend fun removeById(id: String) {
withContext(CommonPool) { withContext(CommonPool) {
dbManager.messageDao().delete(id) retryDB("delete($id)") { dbManager.messageDao().delete(id) }
} }
} }
override suspend fun removeByRoomId(roomId: String) { override suspend fun removeByRoomId(roomId: String) {
withContext(CommonPool) { withContext(CommonPool) {
retryDB("deleteByRoomId($roomId)") {
dbManager.messageDao().deleteByRoomId(roomId) dbManager.messageDao().deleteByRoomId(roomId)
} }
} }
}
override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) { override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) {
retryDB("getUnsentMessages") {
dbManager.messageDao().getUnsentMessages() dbManager.messageDao().getUnsentMessages()
.distinctBy { it.message.message.id } .distinctBy { it.message.message.id }
.let { mapper.map(it) } .let { mapper.map(it) }
} }
}
override suspend fun saveLastSyncDate(roomId: String, timeMillis: Long) { override suspend fun saveLastSyncDate(roomId: String, timeMillis: Long) {
dbManager.sendOperation(Operation.SaveLastSync(MessagesSync(roomId, timeMillis))) dbManager.sendOperation(Operation.SaveLastSync(MessagesSync(roomId, timeMillis)))
} }
override suspend fun getLastSyncDate(roomId: String): Long? = withContext(CommonPool) { override suspend fun getLastSyncDate(roomId: String): Long? = withContext(CommonPool) {
retryDB("getLastSync($roomId)") {
dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp } dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp }
} }
}
} }
\ No newline at end of file
package chat.rocket.android.util package chat.rocket.android.util
import android.database.sqlite.SQLiteDatabaseLockedException
import chat.rocket.common.RocketChatNetworkErrorException import chat.rocket.common.RocketChatNetworkErrorException
import kotlinx.coroutines.experimental.TimeoutCancellationException import kotlinx.coroutines.experimental.TimeoutCancellationException
import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.delay
...@@ -8,6 +9,7 @@ import timber.log.Timber ...@@ -8,6 +9,7 @@ import timber.log.Timber
import kotlin.coroutines.experimental.coroutineContext import kotlin.coroutines.experimental.coroutineContext
const val DEFAULT_RETRY = 3 const val DEFAULT_RETRY = 3
private const val DEFAULT_DB_RETRY = 5
suspend fun <T> retryIO( suspend fun <T> retryIO(
description: String = "<missing description>", description: String = "<missing description>",
...@@ -35,3 +37,30 @@ suspend fun <T> retryIO( ...@@ -35,3 +37,30 @@ suspend fun <T> retryIO(
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled") if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
return block() // last attempt return block() // last attempt
} }
suspend fun <T> retryDB(
description: String = "<missing description>",
times: Int = DEFAULT_DB_RETRY,
initialDelay: Long = 100, // 0.1 second
maxDelay: Long = 500, // 0.5 second
factor: Double = 1.2,
block: suspend () -> T): T
{
var currentDelay = initialDelay
repeat(times - 1) { currentTry ->
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
try {
return block()
} catch (e: SQLiteDatabaseLockedException) {
Timber.d(e, "failed call($currentTry): $description")
e.printStackTrace()
}
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
delay(currentDelay)
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
if (!coroutineContext.isActive) throw TimeoutCancellationException("job canceled")
return block() // last attempt
}
\ No newline at end of file
package chat.rocket.android.push package chat.rocket.android.push
import android.os.Bundle
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.work.Constraints import androidx.work.Constraints
import androidx.work.NetworkType import androidx.work.NetworkType
...@@ -23,9 +24,12 @@ class FirebaseMessagingService : FirebaseMessagingService() { ...@@ -23,9 +24,12 @@ class FirebaseMessagingService : FirebaseMessagingService() {
} }
override fun onMessageReceived(message: RemoteMessage) { override fun onMessageReceived(message: RemoteMessage) {
// XXX - for now this is ok, if we start to do network calls, use a Worker instead message.data?.let { data ->
message.data?.let { val bundle = Bundle()
pushManager.handle(bundleOf(*(it.map { Pair(it.key, it.value) }).toTypedArray())) data.entries.forEach { entry ->
bundle.putString(entry.key, entry.value)
}
pushManager.handle(bundle)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment