com.pubnub.api.subscribe.Subscribe.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pubnub-kotlin Show documentation
Show all versions of pubnub-kotlin Show documentation
PubNub is a cross-platform client-to-client (1:1 and 1:many) push service in the cloud, capable of
broadcasting real-time messages to millions of web and mobile clients simultaneously, in less than a quarter
second!
package com.pubnub.api.subscribe
import com.pubnub.api.PubNub
import com.pubnub.api.PubNubError
import com.pubnub.api.PubNubException
import com.pubnub.api.eventengine.EffectDispatcher
import com.pubnub.api.managers.ListenerManager
import com.pubnub.api.managers.SubscribeEventEngineManager
import com.pubnub.api.subscribe.eventengine.SubscribeEventEngine
import com.pubnub.api.subscribe.eventengine.configuration.EventEnginesConf
import com.pubnub.api.subscribe.eventengine.data.SubscriptionData
import com.pubnub.api.subscribe.eventengine.effect.RetryPolicy
import com.pubnub.api.subscribe.eventengine.effect.SubscribeEffectFactory
import com.pubnub.api.subscribe.eventengine.effect.effectprovider.HandshakeProviderImpl
import com.pubnub.api.subscribe.eventengine.effect.effectprovider.ReceiveMessagesProviderImpl
import com.pubnub.api.subscribe.eventengine.event.SubscribeEvent
import com.pubnub.api.subscribe.eventengine.event.SubscribeEvent.SubscriptionChanged
import com.pubnub.api.subscribe.eventengine.event.SubscribeEvent.SubscriptionRestored
import com.pubnub.api.subscribe.eventengine.event.SubscriptionCursor
import com.pubnub.api.workers.SubscribeMessageProcessor
import java.util.concurrent.Executors
private const val PRESENCE_CHANNEL_SUFFIX = "-pnpres"
internal class Subscribe(
private val subscribeEventEngineManager: SubscribeEventEngineManager,
private val subscriptionData: SubscriptionData = SubscriptionData()
) {
companion object {
internal fun create(
pubNub: PubNub,
listenerManager: ListenerManager,
retryPolicy: RetryPolicy,
eventEnginesConf: EventEnginesConf,
messageProcessor: SubscribeMessageProcessor
): Subscribe {
val subscribeEventEngineManager = createAndStartSubscribeEventEngineManager(
pubNub,
messageProcessor,
eventEnginesConf,
retryPolicy,
listenerManager
)
return Subscribe(subscribeEventEngineManager)
}
private fun createAndStartSubscribeEventEngineManager(
pubNub: PubNub,
messageProcessor: SubscribeMessageProcessor,
eventEnginesConf: EventEnginesConf,
retryPolicy: RetryPolicy,
listenerManager: ListenerManager
): SubscribeEventEngineManager {
val subscribeEffectFactory = SubscribeEffectFactory(
handshakeProvider = HandshakeProviderImpl(pubNub),
receiveMessagesProvider = ReceiveMessagesProviderImpl(pubNub, messageProcessor),
subscribeEventSink = eventEnginesConf.subscribe.eventSink,
policy = retryPolicy,
executorService = Executors.newSingleThreadScheduledExecutor(),
messagesConsumer = listenerManager,
statusConsumer = listenerManager
)
val subscribeEventEngine = SubscribeEventEngine(
effectSink = eventEnginesConf.subscribe.effectSink,
eventSource = eventEnginesConf.subscribe.eventSource
)
val subscribeEffectDispatcher = EffectDispatcher(
effectFactory = subscribeEffectFactory,
effectSource = eventEnginesConf.subscribe.effectSource
)
val subscribeEventEngineManager = SubscribeEventEngineManager(
eventEngine = subscribeEventEngine,
effectDispatcher = subscribeEffectDispatcher,
eventSink = eventEnginesConf.subscribe.eventSink
).apply {
if (pubNub.configuration.enableEventEngine) {
start()
}
}
return subscribeEventEngineManager
}
}
@Synchronized
fun subscribe(
channels: Set,
channelGroups: Set,
withPresence: Boolean,
withTimetoken: Long = 0L,
) {
throwExceptionIfChannelAndChannelGroupIsMissing(channels, channelGroups)
addChannelsToSubscriptionData(channels, withPresence)
addChannelGroupsToSubscriptionData(channelGroups, withPresence)
val channelsInLocalStorage = subscriptionData.channels
val channelGroupsInLocalStorage = subscriptionData.channelGroups
if (withTimetoken != 0L) {
val subscriptionRestoredEvent = SubscriptionRestored(
channelsInLocalStorage,
channelGroupsInLocalStorage,
SubscriptionCursor(withTimetoken, region = null) // we don't know region here. Subscribe response will return region.
)
subscribeEventEngineManager.addEventToQueue(subscriptionRestoredEvent)
} else {
subscribeEventEngineManager.addEventToQueue(
SubscriptionChanged(
channelsInLocalStorage,
channelGroupsInLocalStorage
)
)
}
}
@Synchronized
fun unsubscribe(
channels: Set = emptySet(),
channelGroups: Set = emptySet()
) {
throwExceptionIfChannelAndChannelGroupIsMissing(channels, channelGroups)
removeChannelsFromSubscriptionData(channels)
removeChannelGroupsFromSubscriptionData(channelGroups)
if (subscriptionData.channels.size > 0 || subscriptionData.channelGroups.size > 0) {
val channelsInLocalStorage = subscriptionData.channels
val channelGroupsInLocalStorage = subscriptionData.channelGroups
subscribeEventEngineManager.addEventToQueue(
SubscriptionChanged(
channelsInLocalStorage,
channelGroupsInLocalStorage
)
)
} else {
subscribeEventEngineManager.addEventToQueue(SubscribeEvent.UnsubscribeAll)
}
}
@Synchronized
fun unsubscribeAll() {
removeAllChannelsFromLocalStorage()
removeAllChannelGroupsFromLocalStorage()
subscribeEventEngineManager.addEventToQueue(SubscribeEvent.UnsubscribeAll)
}
@Synchronized
fun getSubscribedChannels(): List {
return subscriptionData.channels.toList().filter { !it.contains(PRESENCE_CHANNEL_SUFFIX) }
}
@Synchronized
fun getSubscribedChannelGroups(): List {
return subscriptionData.channelGroups.toList().filter { !it.contains(PRESENCE_CHANNEL_SUFFIX) }
}
fun disconnect() {
subscribeEventEngineManager.addEventToQueue(SubscribeEvent.Disconnect)
}
fun reconnect() {
subscribeEventEngineManager.addEventToQueue(SubscribeEvent.Reconnect)
}
@Synchronized
fun destroy() {
disconnect()
subscribeEventEngineManager.stop()
}
private fun throwExceptionIfChannelAndChannelGroupIsMissing(
channels: Set,
channelGroups: Set
) {
if (channels.isEmpty() && channelGroups.isEmpty()) {
throw PubNubException(PubNubError.CHANNEL_OR_CHANNEL_GROUP_MISSING)
}
}
private fun addChannelsToSubscriptionData(channels: Set, withPresence: Boolean) {
subscriptionData.channels.addAll(channels)
if (withPresence) {
channels.forEach {
val presenceChannel = "$it$PRESENCE_CHANNEL_SUFFIX"
subscriptionData.channels.add(presenceChannel)
}
}
}
private fun addChannelGroupsToSubscriptionData(channelGroups: Set, withPresence: Boolean) {
subscriptionData.channelGroups.addAll(channelGroups)
if (withPresence) {
channelGroups.forEach {
val presenceChannelGroup = "$it$PRESENCE_CHANNEL_SUFFIX"
subscriptionData.channelGroups.add(presenceChannelGroup)
}
}
}
private fun removeChannelGroupsFromSubscriptionData(channelGroups: Set) {
channelGroups.forEach {
subscriptionData.channelGroups.remove(it)
val presenceChannelGroup = "$it$PRESENCE_CHANNEL_SUFFIX"
subscriptionData.channels.remove(presenceChannelGroup)
}
}
private fun removeChannelsFromSubscriptionData(channels: Set) {
channels.forEach {
subscriptionData.channels.remove(it)
val presenceChannel = "$it$PRESENCE_CHANNEL_SUFFIX"
subscriptionData.channels.remove(presenceChannel)
}
}
private fun removeAllChannelsFromLocalStorage() {
subscriptionData.channels.clear()
}
private fun removeAllChannelGroupsFromLocalStorage() {
subscriptionData.channelGroups.clear()
}
}