@ -30,6 +30,7 @@ import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.successBackground
import java.util.UUID
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
@ -39,15 +40,97 @@ class OpenGroupPoller(private val server: String, private val executorService: S
var isCaughtUp = false
var secondToLastJob : MessageReceiveJob ? = null
private var future : ScheduledFuture < * > ? = null
private var runId : UUID = UUID . randomUUID ( )
companion object {
private const val pollInterval : Long = 4000L
const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000
public fun handleRoomPollInfo (
server : String ,
roomToken : String ,
pollInfo : OpenGroupApi . RoomPollInfo ,
createGroupIfMissingWithPublicKey : String ? = null
) {
val storage = MessagingModuleConfiguration . shared . storage
val groupId = " $server . $roomToken "
val dbGroupId = GroupUtil . getEncodedOpenGroupID ( groupId . toByteArray ( ) )
val existingOpenGroup = storage . getOpenGroup ( roomToken , server )
// If we don't have an existing group and don't have a 'createGroupIfMissingWithPublicKey'
// value then don't process the poll info
val publicKey = ( ( existingOpenGroup ?. publicKey ?: createGroupIfMissingWithPublicKey ) ?: return )
val openGroup = OpenGroup (
server = server ,
room = pollInfo . token ,
name = ( ( pollInfo . details ?. name ?: existingOpenGroup ?. name ) ?: " " ) ,
publicKey = publicKey ,
imageId = ( pollInfo . details ?. imageId ?: existingOpenGroup ?. imageId ) ,
canWrite = pollInfo . write ,
infoUpdates = ( ( pollInfo . details ?. infoUpdates ?: existingOpenGroup ?. infoUpdates ) ?: 0 )
)
// - Open Group changes
storage . updateOpenGroup ( openGroup )
// - User Count
storage . setUserCount ( roomToken , server , pollInfo . activeUsers )
// - Moderators
pollInfo . details ?. moderators ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . MODERATOR )
} )
}
pollInfo . details ?. hiddenModerators ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . HIDDEN _MODERATOR )
} )
}
// - Admins
pollInfo . details ?. admins ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . ADMIN )
} )
}
pollInfo . details ?. hiddenAdmins ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . HIDDEN _ADMIN )
} )
}
// Update the group avatar
if (
(
pollInfo . details != null &&
pollInfo . details . imageId != null && (
pollInfo . details . imageId != existingOpenGroup ?. imageId ||
! storage . hasDownloadedProfilePicture ( dbGroupId )
) &&
storage . getGroupAvatarDownloadJob ( openGroup . server , openGroup . room , pollInfo . details . imageId ) == null
) || (
pollInfo . details == null &&
existingOpenGroup ?. imageId != null &&
! storage . hasDownloadedProfilePicture ( dbGroupId ) &&
storage . getGroupAvatarDownloadJob ( openGroup . server , openGroup . room , existingOpenGroup . imageId ) == null
)
) {
JobQueue . shared . add ( GroupAvatarDownloadJob ( server , roomToken , openGroup . imageId ) )
}
else if (
pollInfo . details != null &&
pollInfo . details . imageId == null &&
existingOpenGroup ?. imageId != null
) {
storage . removeProfilePicture ( dbGroupId )
}
}
}
fun startIfNeeded ( ) {
if ( hasStarted ) { return }
hasStarted = true
runId = UUID . randomUUID ( )
future = executorService ?. schedule ( :: poll , 0 , TimeUnit . MILLISECONDS )
}
@ -57,6 +140,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
}
fun poll ( isPostCapabilitiesRetry : Boolean = false ) : Promise < Unit , Exception > {
val currentRunId = runId
val storage = MessagingModuleConfiguration . shared . storage
val rooms = storage . getAllOpenGroups ( ) . values . filter { it . server == server } . map { it . room }
@ -86,22 +170,30 @@ class OpenGroupPoller(private val server: String, private val executorService: S
isCaughtUp = true
}
}
executorService ?. schedule ( this @OpenGroupPoller :: poll , pollInterval , TimeUnit . MILLISECONDS )
// Only poll again if it's the same poller run
if ( currentRunId == runId ) {
future = executorService ?. schedule ( this @OpenGroupPoller :: poll , pollInterval , TimeUnit . MILLISECONDS )
}
} . fail {
updateCapabilitiesIfNeeded ( isPostCapabilitiesRetry , it )
updateCapabilitiesIfNeeded ( isPostCapabilitiesRetry , currentRunId , it )
} . map { }
}
private fun updateCapabilitiesIfNeeded ( isPostCapabilitiesRetry : Boolean , exception: Exception ) {
private fun updateCapabilitiesIfNeeded ( isPostCapabilitiesRetry : Boolean , currentRunId: UUID , exception: Exception ) {
if ( exception is OnionRequestAPI . HTTPRequestFailedBlindingRequiredException ) {
if ( !is PostCapabilitiesRetry ) {
OpenGroupApi . getCapabilities ( server ) . map {
handleCapabilities ( server , it )
}
executorService ?. schedule ( { poll ( isPostCapabilitiesRetry = true ) } , pollInterval , TimeUnit . MILLISECONDS )
// Only poll again if it's the same poller run
if ( currentRunId == runId ) {
future = executorService ?. schedule ( { poll ( isPostCapabilitiesRetry = true ) } , pollInterval , TimeUnit . MILLISECONDS )
}
}
} else {
executorService ?. schedule ( this @OpenGroupPoller :: poll , pollInterval , TimeUnit . MILLISECONDS )
} else if ( currentRunId == runId ) {
future = executorService?. schedule ( this @OpenGroupPoller :: poll , pollInterval , TimeUnit . MILLISECONDS )
}
}
@ -110,82 +202,6 @@ class OpenGroupPoller(private val server: String, private val executorService: S
storage . setServerCapabilities ( server , capabilities . capabilities )
}
private fun handleRoomPollInfo (
server : String ,
roomToken : String ,
pollInfo : OpenGroupApi . RoomPollInfo
) {
val storage = MessagingModuleConfiguration . shared . storage
val groupId = " $server . $roomToken "
val dbGroupId = GroupUtil . getEncodedOpenGroupID ( groupId . toByteArray ( ) )
val existingOpenGroup = storage . getOpenGroup ( roomToken , server )
val publicKey = existingOpenGroup ?. publicKey ?: return
val openGroup = OpenGroup (
server = server ,
room = pollInfo . token ,
name = if ( pollInfo . details != null ) { pollInfo . details . name } else { existingOpenGroup . name } ,
publicKey = publicKey ,
imageId = if ( pollInfo . details != null ) { pollInfo . details . imageId } else { existingOpenGroup . imageId } ,
canWrite = pollInfo . write ,
infoUpdates = if ( pollInfo . details != null ) { pollInfo . details . infoUpdates } else { existingOpenGroup . infoUpdates }
)
// - Open Group changes
storage . updateOpenGroup ( openGroup )
// - User Count
storage . setUserCount ( roomToken , server , pollInfo . activeUsers )
// - Moderators
pollInfo . details ?. moderators ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . MODERATOR )
} )
}
pollInfo . details ?. hiddenModerators ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . HIDDEN _MODERATOR )
} )
}
// - Admins
pollInfo . details ?. admins ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . ADMIN )
} )
}
pollInfo . details ?. hiddenAdmins ?. let { moderatorList ->
storage . setGroupMemberRoles ( moderatorList . map {
GroupMember ( groupId , it , GroupMemberRole . HIDDEN _ADMIN )
} )
}
// Update the group avatar
if (
(
pollInfo . details != null &&
pollInfo . details . imageId != null && (
pollInfo . details . imageId != existingOpenGroup . imageId ||
! storage . hasDownloadedProfilePicture ( dbGroupId )
) &&
storage . getGroupAvatarDownloadJob ( openGroup . server , openGroup . room , pollInfo . details . imageId ) == null
) || (
pollInfo . details == null &&
existingOpenGroup . imageId != null &&
! storage . hasDownloadedProfilePicture ( dbGroupId ) &&
storage . getGroupAvatarDownloadJob ( openGroup . server , openGroup . room , existingOpenGroup . imageId ) == null
)
) {
JobQueue . shared . add ( GroupAvatarDownloadJob ( server , roomToken , existingOpenGroup . imageId ) )
}
else if (
pollInfo . details != null &&
pollInfo . details . imageId == null &&
existingOpenGroup . imageId != null
) {
storage . removeProfilePicture ( dbGroupId )
}
}
private fun handleMessages (
server : String ,
roomToken : String ,