MessageService.kt
package chat.rocket.android.chatroom.service
import android.app.job.JobParameters
import android.app.job.JobService
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infrastructure.DatabaseMessageMapper
import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository
import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message
import dagger.android.AndroidInjection
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
class MessageService : JobService() {
@Inject
lateinit var factory: ConnectionManagerFactory
@Inject
lateinit var dbFactory: DatabaseManagerFactory
@Inject
lateinit var getAccountsInteractor: GetAccountsInteractor
override fun onCreate() {
super.onCreate()
AndroidInjection.inject(this)
}
override fun onStopJob(params: JobParameters?): Boolean {
return false
}
override fun onStartJob(params: JobParameters?): Boolean {
GlobalScope.launch(Dispatchers.IO) {
getAccountsInteractor.get().forEach { account ->
retrySendingMessages(params, account.serverUrl)
}
jobFinished(params, false)
}
return true
}
private suspend fun retrySendingMessages(params: JobParameters?, serverUrl: String) {
dbFactory.create(serverUrl)?.let { dbManager ->
val messageRepository =
DatabaseMessagesRepository(dbManager, DatabaseMessageMapper(dbManager))
val temporaryMessages = messageRepository.getAllUnsent()
.sortedWith(compareBy(Message::timestamp))
if (temporaryMessages.isNotEmpty()) {
val client = factory.create(serverUrl)?.client
temporaryMessages.forEach { message ->
try {
client?.sendMessage(
message = message.message,
messageId = message.id,
roomId = message.roomId,
avatar = message.avatar,
attachments = message.attachments,
alias = message.senderAlias
)
messageRepository.save(message.copy(synced = true))
Timber.d("Sent scheduled message given by id: ${message.id}")
} catch (ex: Exception) {
Timber.e(ex)
// TODO - remove the generic message when we implement :userId:/message subscription
if (ex is IllegalStateException) {
Timber.e(ex, "Probably a read-only problem...")
// TODO: For now we are only going to reschedule when api is fixed.
messageRepository.removeById(message.id)
jobFinished(params, false)
} else {
// some other error
if (ex.message?.contains("E11000", true) == true) {
// XXX: Temporary solution. We need proper error codes from the api.
messageRepository.save(message.copy(synced = false))
}
jobFinished(params, true)
}
}
}
}
}
}
companion object {
const val RETRY_SEND_MESSAGE_ID = 1
}
}