Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
c3037e3e
Commit
c3037e3e
authored
Nov 13, 2018
by
Lucio Maciel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
retryDB
parent
644d6518
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
114 additions
and
89 deletions
+114
-89
ChatRoomsRepository.kt
...t/android/chatrooms/infrastructure/ChatRoomsRepository.kt
+7
-3
DatabaseManager.kt
app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
+41
-35
DatabaseMessageMapper.kt
...t/android/server/infraestructure/DatabaseMessageMapper.kt
+7
-34
DatabaseMessagesRepository.kt
...roid/server/infraestructure/DatabaseMessagesRepository.kt
+30
-17
IO.kt
app/src/main/java/chat/rocket/android/util/IO.kt
+29
-0
No files found.
app/src/main/java/chat/rocket/android/chatrooms/infrastructure/ChatRoomsRepository.kt
View file @
c3037e3e
...
...
@@ -3,9 +3,12 @@ package chat.rocket.android.chatrooms.infrastructure
import
androidx.lifecycle.LiveData
import
chat.rocket.android.db.ChatRoomDao
import
chat.rocket.android.db.model.ChatRoom
import
chat.rocket.android.util.retryDB
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
>>
{
return
when
(
order
)
{
Order
.
ACTIVITY
->
dao
.
getAll
()
...
...
@@ -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
{
ACTIVITY
,
...
...
app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
View file @
c3037e3e
...
...
@@ -19,6 +19,7 @@ import chat.rocket.android.util.extensions.exhaustive
import
chat.rocket.android.util.extensions.removeTrailingSlash
import
chat.rocket.android.util.extensions.toEntity
import
chat.rocket.android.util.extensions.userId
import
chat.rocket.android.util.retryDB
import
chat.rocket.common.model.BaseRoom
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.SimpleUser
...
...
@@ -96,7 +97,9 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
}
suspend
fun
getRoom
(
id
:
String
)
=
withContext
(
dbManagerContext
)
{
chatRoomDao
().
get
(
id
)
retryDB
(
"getRoom($id)"
)
{
chatRoomDao
().
get
(
id
)
}
}
fun
processUsersBatch
(
users
:
List
<
User
>)
{
...
...
@@ -151,7 +154,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
fun
updateSelfUser
(
myself
:
Myself
)
{
launch
(
dbManagerContext
)
{
val
user
=
userDao
().
getUser
(
myself
.
id
)
val
user
=
retryDB
(
"getUser(${myself.id})"
)
{
userDao
().
getUser
(
myself
.
id
)
}
val
entity
=
user
?.
copy
(
name
=
myself
.
name
?:
user
.
name
,
username
=
myself
.
username
?:
user
.
username
,
...
...
@@ -335,7 +338,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
}
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
)
{
val
chatRoom
=
current
.
chatRoom
...
...
@@ -373,7 +376,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
context
.
getString
(
R
.
string
.
msg_sent_attachment
)
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
)
{
val
userId
=
if
(
type
is
RoomType
.
DirectMessage
)
{
...
...
@@ -539,39 +542,42 @@ 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
)
{
when
(
operation
)
{
is
Operation
.
ClearStatus
->
userDao
().
clearStatus
()
is
Operation
.
UpdateRooms
->
{
Timber
.
d
(
"Running ChatRooms transaction: remove: ${operation.toRemove} - insert: ${operation.toInsert} - update: ${operation.toUpdate}"
)
private
suspend
fun
doOperation
(
operation
:
Operation
)
{
retryDB
(
description
=
"doOperation($operation)"
)
{
when
(
operation
)
{
is
Operation
.
ClearStatus
->
userDao
().
clearStatus
()
is
Operation
.
UpdateRooms
->
{
Timber
.
d
(
"Running ChatRooms transaction: remove: ${operation.toRemove} - insert: ${operation.toInsert} - update: ${operation.toUpdate}"
)
chatRoomDao
().
update
(
operation
.
toInsert
,
operation
.
toUpdate
,
operation
.
toRemove
)
}
is
Operation
.
InsertRooms
->
{
chatRoomDao
().
insertOrReplace
(
operation
.
chatRooms
)
}
is
Operation
.
CleanInsertRooms
->
{
chatRoomDao
().
cleanInsert
(
operation
.
chatRooms
)
}
is
Operation
.
InsertUsers
->
{
val
time
=
measureTimeMillis
{
userDao
().
upsert
(
operation
.
users
)
}
Timber
.
d
(
"Upserted users batch(${operation.users.size}) in $time MS"
)
}
is
Operation
.
InsertUser
->
{
userDao
().
insert
(
operation
.
user
)
}
is
Operation
.
UpsertUser
->
{
userDao
().
upsert
(
operation
.
user
)
}
is
Operation
.
InsertMessages
->
{
messageDao
().
insert
(
operation
.
list
)
}
is
Operation
.
SaveLastSync
->
{
messageDao
().
saveLastSync
(
operation
.
sync
)
}
}.
exhaustive
chatRoomDao
().
update
(
operation
.
toInsert
,
operation
.
toUpdate
,
operation
.
toRemove
)
}
is
Operation
.
InsertRooms
->
{
chatRoomDao
().
insertOrReplace
(
operation
.
chatRooms
)
}
is
Operation
.
CleanInsertRooms
->
{
chatRoomDao
().
cleanInsert
(
operation
.
chatRooms
)
}
is
Operation
.
InsertUsers
->
{
val
time
=
measureTimeMillis
{
userDao
().
upsert
(
operation
.
users
)
}
Timber
.
d
(
"Upserted users batch(${operation.users.size}) in $time MS"
)
}
is
Operation
.
InsertUser
->
{
userDao
().
insert
(
operation
.
user
)
}
is
Operation
.
UpsertUser
->
{
userDao
().
upsert
(
operation
.
user
)
}
is
Operation
.
InsertMessages
->
{
messageDao
().
insert
(
operation
.
list
)
}
is
Operation
.
SaveLastSync
->
{
messageDao
().
saveLastSync
(
operation
.
sync
)
}
}.
exhaustive
}
}
}
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessageMapper.kt
View file @
c3037e3e
...
...
@@ -7,6 +7,7 @@ import chat.rocket.android.db.model.FullMessage
import
chat.rocket.android.db.model.ReactionEntity
import
chat.rocket.android.db.model.UrlEntity
import
chat.rocket.android.db.model.UserEntity
import
chat.rocket.android.util.retryDB
import
chat.rocket.common.model.SimpleRoom
import
chat.rocket.common.model.SimpleUser
import
chat.rocket.core.model.Message
...
...
@@ -135,14 +136,18 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
with
(
attachment
)
{
val
fields
=
if
(
hasFields
)
{
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getAttachmentFields
(
attachment
.
_id
)
retryDB
(
"getAttachmentFields(${attachment._id})"
)
{
dbManager
.
messageDao
().
getAttachmentFields
(
attachment
.
_id
)
}
}.
map
{
Field
(
it
.
title
,
it
.
value
)
}
}
else
{
null
}
val
actions
=
if
(
hasActions
)
{
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getAttachmentActions
(
attachment
.
_id
)
retryDB
(
"getAttachmentActions(${attachment._id})"
)
{
dbManager
.
messageDao
().
getAttachmentActions
(
attachment
.
_id
)
}
}.
mapNotNull
{
mapAction
(
it
)
}
}
else
{
null
...
...
@@ -183,29 +188,6 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
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
?
{
return
when
(
action
.
type
)
{
"button"
->
ButtonAction
(
action
.
type
,
action
.
text
,
action
.
url
,
action
.
isWebView
,
...
...
@@ -214,13 +196,4 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
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
app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessagesRepository.kt
View file @
c3037e3e
...
...
@@ -4,6 +4,7 @@ import chat.rocket.android.db.DatabaseManager
import
chat.rocket.android.db.Operation
import
chat.rocket.android.db.model.MessagesSync
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.android.util.retryDB
import
chat.rocket.core.model.Message
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
...
...
@@ -14,25 +15,31 @@ class DatabaseMessagesRepository(
)
:
MessagesRepository
{
override
suspend
fun
getById
(
id
:
String
):
Message
?
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getMessageById
(
id
)
?.
let
{
message
->
mapper
.
map
(
message
)
}
retryDB
(
"getMessageById($id)"
)
{
dbManager
.
messageDao
().
getMessageById
(
id
)
?.
let
{
message
->
mapper
.
map
(
message
)
}
}
}
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
// duplicate rows (something related to our JOINS and relations on Room)
dbManager
.
messageDao
().
getMessagesByRoomId
(
roomId
)
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
messages
->
mapper
.
map
(
messages
)
}
retryDB
(
"getMessagesByRoomId($roomId)"
)
{
dbManager
.
messageDao
().
getMessagesByRoomId
(
roomId
)
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
messages
->
mapper
.
map
(
messages
)
}
}
}
override
suspend
fun
getRecentMessages
(
roomId
:
String
,
count
:
Long
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getRecentMessagesByRoomId
(
roomId
,
count
)
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
messages
->
mapper
.
map
(
messages
)
}
retryDB
(
"getRecentMessagesByRoomId($roomId, $count)"
)
{
dbManager
.
messageDao
().
getRecentMessagesByRoomId
(
roomId
,
count
)
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
messages
->
mapper
.
map
(
messages
)
}
}
}
override
suspend
fun
save
(
message
:
Message
)
{
...
...
@@ -45,20 +52,24 @@ class DatabaseMessagesRepository(
override
suspend
fun
removeById
(
id
:
String
)
{
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
delete
(
id
)
retryDB
(
"delete($id)"
)
{
dbManager
.
messageDao
().
delete
(
id
)
}
}
}
override
suspend
fun
removeByRoomId
(
roomId
:
String
)
{
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
deleteByRoomId
(
roomId
)
retryDB
(
"deleteByRoomId($roomId)"
)
{
dbManager
.
messageDao
().
deleteByRoomId
(
roomId
)
}
}
}
override
suspend
fun
getAllUnsent
():
List
<
Message
>
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getUnsentMessages
()
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
mapper
.
map
(
it
)
}
retryDB
(
"getUnsentMessages"
)
{
dbManager
.
messageDao
().
getUnsentMessages
()
.
distinctBy
{
it
.
message
.
message
.
id
}
.
let
{
mapper
.
map
(
it
)
}
}
}
override
suspend
fun
saveLastSyncDate
(
roomId
:
String
,
timeMillis
:
Long
)
{
...
...
@@ -66,6 +77,8 @@ class DatabaseMessagesRepository(
}
override
suspend
fun
getLastSyncDate
(
roomId
:
String
):
Long
?
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getLastSync
(
roomId
)
?.
let
{
it
.
timestamp
}
retryDB
(
"getLastSync($roomId)"
)
{
dbManager
.
messageDao
().
getLastSync
(
roomId
)
?.
let
{
it
.
timestamp
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/IO.kt
View file @
c3037e3e
package
chat.rocket.android.util
import
android.database.sqlite.SQLiteDatabaseLockedException
import
chat.rocket.common.RocketChatNetworkErrorException
import
kotlinx.coroutines.experimental.TimeoutCancellationException
import
kotlinx.coroutines.experimental.delay
...
...
@@ -8,6 +9,7 @@ import timber.log.Timber
import
kotlin.coroutines.experimental.coroutineContext
const
val
DEFAULT_RETRY
=
3
private
const
val
DEFAULT_DB_RETRY
=
5
suspend
fun
<
T
>
retryIO
(
description
:
String
=
"<missing description>"
,
...
...
@@ -32,6 +34,33 @@ suspend fun <T> retryIO(
currentDelay
=
(
currentDelay
*
factor
).
toLong
().
coerceAtMost
(
maxDelay
)
}
if
(!
coroutineContext
.
isActive
)
throw
TimeoutCancellationException
(
"job canceled"
)
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment