Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.pubnub.internal
import com.pubnub.api.PubNubException
import com.pubnub.api.UserId
import com.pubnub.api.crypto.CryptoModule
import com.pubnub.api.enums.PNPushEnvironment
import com.pubnub.api.enums.PNPushType
import com.pubnub.api.models.consumer.PNBoundedPage
import com.pubnub.api.models.consumer.access_manager.v3.PNToken
import com.pubnub.api.models.consumer.message_actions.PNMessageAction
import com.pubnub.api.models.consumer.objects.PNPage
import com.pubnub.api.v2.BasePNConfiguration
import com.pubnub.api.v2.callbacks.BaseEventListener
import com.pubnub.api.v2.subscriptions.BaseSubscription
import com.pubnub.api.v2.subscriptions.EmptyOptions
import com.pubnub.api.v2.subscriptions.SubscriptionCursor
import com.pubnub.api.v2.subscriptions.SubscriptionOptions
import com.pubnub.internal.crypto.decryptString
import com.pubnub.internal.crypto.encryptString
import com.pubnub.internal.endpoints.DeleteMessagesEndpoint
import com.pubnub.internal.endpoints.FetchMessagesEndpoint
import com.pubnub.internal.endpoints.HistoryEndpoint
import com.pubnub.internal.endpoints.MessageCountsEndpoint
import com.pubnub.internal.endpoints.TimeEndpoint
import com.pubnub.internal.endpoints.access.GrantEndpoint
import com.pubnub.internal.endpoints.access.GrantTokenEndpoint
import com.pubnub.internal.endpoints.access.RevokeTokenEndpoint
import com.pubnub.internal.endpoints.channel_groups.AddChannelChannelGroupEndpoint
import com.pubnub.internal.endpoints.channel_groups.AllChannelsChannelGroupEndpoint
import com.pubnub.internal.endpoints.channel_groups.DeleteChannelGroupEndpoint
import com.pubnub.internal.endpoints.channel_groups.ListAllChannelGroupEndpoint
import com.pubnub.internal.endpoints.channel_groups.RemoveChannelChannelGroupEndpoint
import com.pubnub.internal.endpoints.files.DeleteFileEndpoint
import com.pubnub.internal.endpoints.files.DownloadFileEndpoint
import com.pubnub.internal.endpoints.files.GenerateUploadUrlEndpoint
import com.pubnub.internal.endpoints.files.GetFileUrlEndpoint
import com.pubnub.internal.endpoints.files.ListFilesEndpoint
import com.pubnub.internal.endpoints.files.PublishFileMessageEndpoint
import com.pubnub.internal.endpoints.files.SendFileEndpoint
import com.pubnub.internal.endpoints.files.UploadFileEndpoint
import com.pubnub.internal.endpoints.message_actions.AddMessageActionEndpoint
import com.pubnub.internal.endpoints.message_actions.GetMessageActionsEndpoint
import com.pubnub.internal.endpoints.message_actions.RemoveMessageActionEndpoint
import com.pubnub.internal.endpoints.objects.channel.GetAllChannelMetadataEndpoint
import com.pubnub.internal.endpoints.objects.channel.GetChannelMetadataEndpoint
import com.pubnub.internal.endpoints.objects.channel.RemoveChannelMetadataEndpoint
import com.pubnub.internal.endpoints.objects.channel.SetChannelMetadataEndpoint
import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters
import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam
import com.pubnub.internal.endpoints.objects.member.GetChannelMembersEndpoint
import com.pubnub.internal.endpoints.objects.member.ManageChannelMembersEndpoint
import com.pubnub.internal.endpoints.objects.membership.GetMembershipsEndpoint
import com.pubnub.internal.endpoints.objects.membership.ManageMembershipsEndpoint
import com.pubnub.internal.endpoints.objects.uuid.GetAllUUIDMetadataEndpoint
import com.pubnub.internal.endpoints.objects.uuid.GetUUIDMetadataEndpoint
import com.pubnub.internal.endpoints.objects.uuid.RemoveUUIDMetadataEndpoint
import com.pubnub.internal.endpoints.objects.uuid.SetUUIDMetadataEndpoint
import com.pubnub.internal.endpoints.presence.GetStateEndpoint
import com.pubnub.internal.endpoints.presence.HereNowEndpoint
import com.pubnub.internal.endpoints.presence.SetStateEndpoint
import com.pubnub.internal.endpoints.presence.WhereNowEndpoint
import com.pubnub.internal.endpoints.pubsub.PublishEndpoint
import com.pubnub.internal.endpoints.pubsub.SignalEndpoint
import com.pubnub.internal.endpoints.push.AddChannelsToPushEndpoint
import com.pubnub.internal.endpoints.push.ListPushProvisionsEndpoint
import com.pubnub.internal.endpoints.push.RemoveAllPushChannelsForDeviceEndpoint
import com.pubnub.internal.endpoints.push.RemoveChannelsFromPushEndpoint
import com.pubnub.internal.managers.BasePathManager
import com.pubnub.internal.managers.DuplicationManager
import com.pubnub.internal.managers.ListenerManager
import com.pubnub.internal.managers.MapperManager
import com.pubnub.internal.managers.PublishSequenceManager
import com.pubnub.internal.managers.RetrofitManager
import com.pubnub.internal.managers.TokenManager
import com.pubnub.internal.managers.TokenParser
import com.pubnub.internal.models.consumer.access_manager.sum.SpacePermissions
import com.pubnub.internal.models.consumer.access_manager.sum.UserPermissions
import com.pubnub.internal.models.consumer.access_manager.sum.toChannelGrant
import com.pubnub.internal.models.consumer.access_manager.sum.toUuidGrant
import com.pubnub.internal.models.consumer.access_manager.v3.ChannelGrant
import com.pubnub.internal.models.consumer.access_manager.v3.ChannelGroupGrant
import com.pubnub.internal.models.consumer.access_manager.v3.UUIDGrant
import com.pubnub.internal.models.consumer.objects.PNKey
import com.pubnub.internal.models.consumer.objects.PNMemberKey
import com.pubnub.internal.models.consumer.objects.PNMembershipKey
import com.pubnub.internal.models.consumer.objects.PNSortKey
import com.pubnub.internal.models.consumer.objects.member.MemberInput
import com.pubnub.internal.models.consumer.objects.member.PNUUIDDetailsLevel
import com.pubnub.internal.models.consumer.objects.membership.ChannelMembershipInput
import com.pubnub.internal.models.consumer.objects.membership.PNChannelDetailsLevel
import com.pubnub.internal.presence.Presence
import com.pubnub.internal.presence.eventengine.data.PresenceData
import com.pubnub.internal.presence.eventengine.effect.effectprovider.HeartbeatProviderImpl
import com.pubnub.internal.presence.eventengine.effect.effectprovider.LeaveProviderImpl
import com.pubnub.internal.subscribe.PRESENCE_CHANNEL_SUFFIX
import com.pubnub.internal.subscribe.Subscribe
import com.pubnub.internal.subscribe.eventengine.configuration.EventEnginesConf
import com.pubnub.internal.v2.entities.BaseChannelGroupImpl
import com.pubnub.internal.v2.entities.BaseChannelImpl
import com.pubnub.internal.v2.entities.ChannelGroupName
import com.pubnub.internal.v2.entities.ChannelName
import com.pubnub.internal.v2.subscription.BaseSubscriptionImpl
import com.pubnub.internal.workers.SubscribeMessageProcessor
import java.io.InputStream
import java.util.Date
import java.util.UUID
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import kotlin.time.Duration.Companion.seconds
class PubNubCore internal constructor(
val configuration: BasePNConfiguration,
val listenerManager: ListenerManager,
eventEnginesConf: EventEnginesConf = EventEnginesConf(),
private val pnsdkName: String,
) {
companion object {
internal const val TIMESTAMP_DIVIDER = 1000
internal const val SDK_VERSION = PUBNUB_VERSION
internal const val MAX_SEQUENCE = 65535
@JvmStatic
fun timestamp() = (Date().time / TIMESTAMP_DIVIDER).toInt()
}
private val subscriptionFactory: SubscriptionFactory> =
{ channels, channelGroups, options ->
object : BaseSubscriptionImpl(this, channels, channelGroups, options) {
override fun addListener(listener: BaseEventListener) {
// not used
}
}
}
//region Managers
/**
* Manage and parse JSON
*/
val mapper = MapperManager()
private val numberOfThreadsInPool = Integer.min(Runtime.getRuntime().availableProcessors(), 8)
internal val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(numberOfThreadsInPool)
private val basePathManager = BasePathManager(configuration)
internal val retrofitManager = RetrofitManager(this, configuration)
internal val publishSequenceManager = PublishSequenceManager(MAX_SEQUENCE)
internal val tokenManager: TokenManager = TokenManager()
private val tokenParser: TokenParser = TokenParser()
private val presenceData = PresenceData()
private val subscribe =
Subscribe.create(
this,
listenerManager,
eventEnginesConf,
SubscribeMessageProcessor(this, DuplicationManager(configuration)),
presenceData,
configuration.maintainPresenceState,
)
private val presence =
Presence.create(
heartbeatProvider = HeartbeatProviderImpl(this),
leaveProvider = LeaveProviderImpl(this),
heartbeatInterval = configuration.heartbeatInterval.seconds,
suppressLeaveEvents = configuration.suppressLeaveEvents,
heartbeatNotificationOptions = configuration.heartbeatNotificationOptions,
listenerManager = listenerManager,
eventEngineConf = eventEnginesConf.presence,
presenceData = presenceData,
sendStateWithHeartbeat = configuration.maintainPresenceState,
executorService = executorService,
)
//endregion
/**
* Unique id of this PubNub instance.
*
* @see [BasePNConfiguration.includeInstanceIdentifier]
*/
val instanceId = UUID.randomUUID().toString()
//region Internal
internal fun baseUrl() = basePathManager.basePath()
internal fun requestId() = UUID.randomUUID().toString()
//endregion
fun generatePnsdk(): String {
val joinedSuffixes = configuration.pnsdkSuffixes.toSortedMap().values.joinToString(" ")
return "$pnsdkName/$SDK_VERSION" +
if (joinedSuffixes.isNotBlank()) {
" $joinedSuffixes"
} else {
""
}
}
//region Publish
/**
* Send a message to all subscribers of a channel.
*
* To publish a message you must first specify a valid [BasePNConfiguration.publishKey].
* A successfully published message is replicated across the PubNub Real-Time Network and sent
* simultaneously to all subscribed clients on a channel.
*
* Messages in transit can be secured from potential eavesdroppers with SSL/TLS by setting
* [BasePNConfiguration.secure] to `true` during initialization.
*
* **Publish Anytime**
*
*
* It is not required to be subscribed to a channel in order to publish to that channel.
*
* **Message Data:**
*
*
* The message argument can contain any JSON serializable data, including: Objects, Arrays, Integers and Strings.
* Data should not contain special Java/Kotlin classes or functions as these will not serialize.
* String content can include any single-byte or multi-byte UTF-8 character.
*
*
* @param message The payload.
* **Warning:** It is important to note that you should not serialize JSON
* when sending signals/messages via PubNub.
* Why? Because the serialization is done for you automatically.
* Instead just pass the full object as the message payload.
* PubNub takes care of everything for you.
* @param channel Destination of the message.
* @param meta Metadata object which can be used with the filtering ability.
* @param shouldStore Store in history.
* If not specified, then the history configuration of the key is used.
* @param usePost Use HTTP POST to publish. Default is `false`
* @param replicate Replicate the message. Is set to `true` by default.
* @param ttl Set a per message time to live in storage.
* - If `shouldStore = true`, and `ttl = 0`, the message is stored
* with no expiry time.
* - If `shouldStore = true` and `ttl = X` (`X` is an Integer value),
* the message is stored with an expiry time of `X` hours.
* - If `shouldStore = false`, the `ttl` parameter is ignored.
* - If ttl isn't specified, then expiration of the message defaults
* back to the expiry value for the key.
*/
fun publish(
channel: String,
message: Any,
meta: Any? = null,
shouldStore: Boolean? = null,
usePost: Boolean = false,
replicate: Boolean = true,
ttl: Int? = null,
) = PublishEndpoint(
pubnub = this,
channel = channel,
message = message,
meta = meta,
shouldStore = shouldStore,
usePost = usePost,
replicate = replicate,
ttl = ttl,
)
/**
* Send a message to PubNub Functions Event Handlers.
*
* These messages will go directly to any Event Handlers registered on the channel that you fire to
* and will trigger their execution. The content of the fired request will be available for processing
* within the Event Handler.
*
* The message sent via `fire()` isn't replicated, and so won't be received by any subscribers to the channel.
* The message is also not stored in history.
*
*
* @param message The payload.
* **Warning:** It is important to note that you should not serialize JSON
* when sending signals/messages via PubNub.
* Why? Because the serialization is done for you automatically.
* Instead just pass the full object as the message payload.
* PubNub takes care of everything for you.
* @param channel Destination of the message.
* @param meta Metadata object which can be used with the filtering ability.
* If not specified, then the history configuration of the key is used.
* @param usePost Use HTTP POST to publish. Default is `false`
* @param ttl Set a per message time to live in storage.
* - If `shouldStore = true`, and `ttl = 0`, the message is stored
* with no expiry time.
* - If `shouldStore = true` and `ttl = X` (`X` is an Integer value),
* the message is stored with an expiry time of `X` hours.
* - If `shouldStore = false`, the `ttl` parameter is ignored.
* - If ttl isn't specified, then expiration of the message defaults
* back to the expiry value for the key.
*/
fun fire(
channel: String,
message: Any,
meta: Any? = null,
usePost: Boolean = false,
ttl: Int? = null,
) = publish(
channel = channel,
message = message,
meta = meta,
shouldStore = false,
usePost = usePost,
replicate = false,
ttl = ttl,
)
/**
* Send a signal to all subscribers of a channel.
*
* By default, signals are limited to a message payload size of 30 bytes.
* This limit applies only to the payload, and not to the URI or headers.
* If you require a larger payload size, please [contact support](mailto:[email protected]).
*
* @param channel The channel which the signal will be sent to.
* @param message The payload which will be serialized and sent.
*/
fun signal(
channel: String,
message: Any,
) = SignalEndpoint(pubnub = this, channel = channel, message = message)
//endregion
private fun subscribeInternal(
channels: List = emptyList(),
channelGroups: List = emptyList(),
withPresence: Boolean = false,
withTimetoken: Long = 0L,
) {
subscribe.subscribe(channels.toSet(), channelGroups.toSet(), withPresence, withTimetoken)
if (!configuration.managePresenceListManually) {
presence.joined(
channels.filterNot { it.endsWith(PRESENCE_CHANNEL_SUFFIX) }.toSet(),
channelGroups.filterNot { it.endsWith(PRESENCE_CHANNEL_SUFFIX) }.toSet(),
)
}
}
private fun unsubscribeInternal(
channels: List = emptyList(),
channelGroups: List = emptyList(),
) {
val channelSetWithoutPresence = channels.filter { !it.endsWith(PRESENCE_CHANNEL_SUFFIX) }.toSet()
val groupSetWithoutPresence = channelGroups.filter { !it.endsWith(PRESENCE_CHANNEL_SUFFIX) }.toSet()
subscribe.unsubscribe(channelSetWithoutPresence, groupSetWithoutPresence)
if (!configuration.managePresenceListManually) {
presence.left(channelSetWithoutPresence, groupSetWithoutPresence)
}
}
/**
* Unsubscribe from all channels and all channel groups
*/
@Synchronized
fun unsubscribeAll() {
synchronized(lockChannelsAndGroups) {
channelSubscriptions.clear()
channelGroupSubscriptions.clear()
subscribe.unsubscribeAll()
presence.leftAll()
}
}
/**
* Queries the local subscribe loop for channels currently in the mix.
*
* @return A list of channels the client is currently subscribed to.
*/
fun getSubscribedChannels() = subscribe.getSubscribedChannels()
/**
* Queries the local subscribe loop for channel groups currently in the mix.
*
* @return A list of channel groups the client is currently subscribed to.
*/
fun getSubscribedChannelGroups() = subscribe.getSubscribedChannelGroups()
//endregion
//region MobilePush
/**
* Enable push notifications on provided set of channels.
*
* @param pushType Accepted values: FCM, APNS, MPNS, APNS2.
* @see [PNPushType]
* @param channels Channels to add push notifications to.
* @param deviceId The device ID (token) to associate with push notifications.
* @param environment Environment within which device should manage list of channels with enabled notifications
* (works only if [pushType] set to [PNPushType.APNS2]).
* @param topic Notifications topic name (usually it is bundle identifier of application for Apple platform).
* Required only if pushType set to [PNPushType.APNS2].
*/
fun addPushNotificationsOnChannels(
pushType: PNPushType,
channels: List,
deviceId: String,
topic: String? = null,
environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT,
) = AddChannelsToPushEndpoint(
pubnub = this,
pushType = pushType,
channels = channels,
deviceId = deviceId,
topic = topic,
environment = environment,
)
/**
* Request a list of all channels on which push notifications have been enabled using specified [ListPushProvisionsEndpoint.deviceId].
*
* @param pushType Accepted values: FCM, APNS, MPNS, APNS2. @see [PNPushType]
* @param deviceId The device ID (token) to associate with push notifications.
* @param environment Environment within which device should manage list of channels with enabled notifications
* (works only if [pushType] set to [PNPushType.APNS2]).
* @param topic Notifications topic name (usually it is bundle identifier of application for Apple platform).
* Required only if pushType set to [PNPushType.APNS2].
*/
fun auditPushChannelProvisions(
pushType: PNPushType,
deviceId: String,
topic: String? = null,
environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT,
) = ListPushProvisionsEndpoint(
pubnub = this,
pushType = pushType,
deviceId = deviceId,
topic = topic,
environment = environment,
)
/**
* Disable push notifications on provided set of channels.
*
* @param pushType Accepted values: FCM, APNS, MPNS, APNS2. @see [PNPushType]
* @param channels Channels to remove push notifications from.
* @param deviceId The device ID (token) associated with push notifications.
* @param environment Environment within which device should manage list of channels with enabled notifications
* (works only if [pushType] set to [PNPushType.APNS2]).
* @param topic Notifications topic name (usually it is bundle identifier of application for Apple platform).
* Required only if pushType set to [PNPushType.APNS2].
*/
fun removePushNotificationsFromChannels(
pushType: PNPushType,
channels: List,
deviceId: String,
topic: String? = null,
environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT,
) = RemoveChannelsFromPushEndpoint(
pubnub = this,
pushType = pushType,
channels = channels,
deviceId = deviceId,
topic = topic,
environment = environment,
)
/**
* Disable push notifications from all channels registered with the specified [RemoveAllPushChannelsForDeviceEndpoint.deviceId].
*
* @param pushType Accepted values: FCM, APNS, MPNS, APNS2. @see [PNPushType]
* @param deviceId The device ID (token) to associate with push notifications.
* @param environment Environment within which device should manage list of channels with enabled notifications
* (works only if [pushType] set to [PNPushType.APNS2]).
* @param topic Notifications topic name (usually it is bundle identifier of application for Apple platform).
* Required only if pushType set to [PNPushType.APNS2].
*/
fun removeAllPushNotificationsFromDeviceWithPushToken(
pushType: PNPushType,
deviceId: String,
topic: String? = null,
environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT,
) = RemoveAllPushChannelsForDeviceEndpoint(
pubnub = this,
pushType = pushType,
deviceId = deviceId,
topic = topic,
environment = environment,
)
//endregion
//region StoragePlayback
/**
* Fetch historical messages of a channel.
*
* It is possible to control how messages are returned and in what order, for example you can:
* - Search for messages starting on the newest end of the timeline (default behavior - `reverse = false`)
* - Search for messages from the oldest end of the timeline by setting `reverse` to `true`.
* - Page through results by providing a `start` OR `end` timetoken.
* - Retrieve a slice of the time line by providing both a `start` AND `end` timetoken.
* - Limit the number of messages to a specific quantity using the `count` parameter.
*
* **Start & End parameter usage clarity:**
* - If only the `start` parameter is specified (without `end`),
* you will receive messages that are older than and up to that `start` timetoken value.
* - If only the `end` parameter is specified (without `start`)
* you will receive messages that match that end timetoken value and newer.
* - Specifying values for both start and end parameters
* will return messages between those timetoken values (inclusive on the `end` value)
* - Keep in mind that you will still receive a maximum of 100 messages
* even if there are more messages that meet the timetoken values.
* Iterative calls to history adjusting the start timetoken is necessary to page through the full set of results
* if more than 100 messages meet the timetoken values.
*
* @param channel Channel to return history messages from.
* @param start Timetoken delimiting the start of time slice (exclusive) to pull messages from.
* @param end Timetoken delimiting the end of time slice (inclusive) to pull messages from.
* @param count Specifies the number of historical messages to return.
* Default and maximum value is `100`.
* @param reverse Whether to traverse the time ine in reverse starting with the oldest message first.
* Default is `false`.
* @param includeTimetoken Whether to include message timetokens in the response.
* Defaults to `false`.
* @param includeMeta Whether to include message metadata in response.
* Defaults to `false`.
*/
fun history(
channel: String,
start: Long? = null,
end: Long? = null,
count: Int = HistoryEndpoint.MAX_COUNT,
reverse: Boolean = false,
includeTimetoken: Boolean = false,
includeMeta: Boolean = false,
) = HistoryEndpoint(
pubnub = this,
channel = channel,
start = start,
end = end,
count = count,
reverse = reverse,
includeTimetoken = includeTimetoken,
includeMeta = includeMeta,
)
/**
* Fetch historical messages from multiple channels.
* The `includeMessageActions` flag also allows you to fetch message actions along with the messages.
*
* It's possible to control how messages are returned and in what order. For example, you can:
* - Search for messages starting on the newest end of the timeline.
* - Search for messages from the oldest end of the timeline.
* - Page through results by providing a `start` OR `end` time token.
* - Retrieve a slice of the time line by providing both a `start` AND `end` time token.
* - Limit the number of messages to a specific quantity using the `count` parameter.
* - Batch history returns up to 25 messages per channel, on a maximum of 500 channels.
* Use the start and end timestamps to page through the next batch of messages.
*
* **Start & End parameter usage clarity:**
* - If you specify only the `start` parameter (without `end`),
* you will receive messages that are older than and up to that `start` timetoken.
* - If you specify only the `end` parameter (without `start`),
* you will receive messages from that `end` timetoken and newer.
* - Specify values for both `start` and `end` parameters to retrieve messages between those timetokens
* (inclusive of the `end` value).
* - Keep in mind that you will still receive a maximum of 25 messages
* even if there are more messages that meet the timetoken values.
* - Iterative calls to history adjusting the start timetoken is necessary to page through the full set of results
* if more than 25 messages meet the timetoken values.
*
* @param channels Channels to return history messages from.
* @param maximumPerChannel Specifies the number of historical messages to return per channel.
* If [includeMessageActions] is `false`, then `1` is the default (and maximum) value.
* Otherwise it's `25`.
* @param start Timetoken delimiting the start of time slice (exclusive) to pull messages from.
* @param end Time token delimiting the end of time slice (inclusive) to pull messages from.
* @param includeMeta Whether to include message metadata in response.
* Defaults to `false`.
* @param includeMessageActions Whether to include message actions in response.
* Defaults to `false`.
*/
@Deprecated(
replaceWith =
ReplaceWith(
"fetchMessages(channels = channels, page = PNBoundedPage(start = start, end = end, " +
"limit = maximumPerChannel),includeMeta = includeMeta, " +
"includeMessageActions = includeMessageActions, includeMessageType = includeMessageType)",
"com.pubnub.api.models.consumer.PNBoundedPage",
),
level = DeprecationLevel.WARNING,
message = "Use fetchMessages(String, PNBoundedPage, Boolean, Boolean, Boolean) instead",
)
fun fetchMessages(
channels: List,
maximumPerChannel: Int = 0,
start: Long? = null,
end: Long? = null,
includeMeta: Boolean = false,
includeMessageActions: Boolean = false,
includeMessageType: Boolean = true,
): FetchMessagesEndpoint =
fetchMessages(
channels = channels,
page = PNBoundedPage(start = start, end = end, limit = maximumPerChannel),
includeMeta = includeMeta,
includeMessageActions = includeMessageActions,
includeMessageType = includeMessageType,
)
/**
* Fetch historical messages from multiple channels.
* The `includeMessageActions` flag also allows you to fetch message actions along with the messages.
*
* It's possible to control how messages are returned and in what order. For example, you can:
* - Search for messages starting on the newest end of the timeline.
* - Search for messages from the oldest end of the timeline.
* - Page through results by providing a `start` OR `end` time token.
* - Retrieve a slice of the time line by providing both a `start` AND `end` time token.
* - Limit the number of messages to a specific quantity using the `limit` parameter.
* - Batch history returns up to 25 messages per channel, on a maximum of 500 channels.
* Use the start and end timestamps to page through the next batch of messages.
*
* **Start & End parameter usage clarity:**
* - If you specify only the `start` parameter (without `end`),
* you will receive messages that are older than and up to that `start` timetoken.
* - If you specify only the `end` parameter (without `start`),
* you will receive messages from that `end` timetoken and newer.
* - Specify values for both `start` and `end` parameters to retrieve messages between those timetokens
* (inclusive of the `end` value).
* - Keep in mind that you will still receive a maximum of 25 messages
* even if there are more messages that meet the timetoken values.
* - Iterative calls to history adjusting the start timetoken is necessary to page through the full set of results
* if more than 25 messages meet the timetoken values.
*
* @param channels Channels to return history messages from.
* @param page The paging object used for pagination. @see [PNBoundedPage]
* @param includeUUID Whether to include publisher uuid with each history message. Defaults to `true`.
* @param includeMeta Whether to include message metadata in response.
* Defaults to `false`.
* @param includeMessageActions Whether to include message actions in response.
* Defaults to `false`.
* @param includeMessageType Whether to include message type in response.
* Defaults to `false`.
*/
fun fetchMessages(
channels: List,
page: PNBoundedPage = PNBoundedPage(),
includeUUID: Boolean = true,
includeMeta: Boolean = false,
includeMessageActions: Boolean = false,
includeMessageType: Boolean = true,
) = FetchMessagesEndpoint(
pubnub = this,
channels = channels,
page = page,
includeUUID = includeUUID,
includeMeta = includeMeta,
includeMessageActions = includeMessageActions,
includeMessageType = includeMessageType,
)
/**
* Removes messages from the history of a specific channel.
*
* NOTE: There is a setting to accept delete from history requests for a key,
* which you must enable by checking the Enable `Delete-From-History` checkbox
* in the key settings for your key in the Administration Portal.
*
* Requires Initialization with secret key.
*
* @param channels Channels to delete history messages from.
* @param start Timetoken delimiting the start of time slice (exclusive) to delete messages from.
* @param end Time token delimiting the end of time slice (inclusive) to delete messages from.
*/
fun deleteMessages(
channels: List,
start: Long? = null,
end: Long? = null,
) = DeleteMessagesEndpoint(pubnub = this, channels = channels, start = start, end = end)
/**
* Fetches the number of messages published on one or more channels since a given time.
* The count returned is the number of messages in history with a timetoken value greater
* than the passed value in the [MessageCountsEndpoint.channelsTimetoken] parameter.
*
* @param channels Channels to fetch the message count from.
* @param channelsTimetoken List of timetokens, in order of the channels list.
* Specify a single timetoken to apply it to all channels.
* Otherwise, the list of timetokens must be the same length as the list of channels.
*/
fun messageCounts(
channels: List,
channelsTimetoken: List,
) = MessageCountsEndpoint(pubnub = this, channels = channels, channelsTimetoken = channelsTimetoken)
//endregion
//region Presence
/**
* Obtain information about the current state of a channel including a list of unique user IDs
* currently subscribed to the channel and the total occupancy count of the channel.
*
* @param channels The channels to get the 'here now' details of.
* Leave empty for a 'global her now'.
* @param channelGroups The channel groups to get the 'here now' details of.
* Leave empty for a 'global her now'.
* @param includeState Whether the response should include presence state information, if available.
* Defaults to `false`.
* @param includeUUIDs Whether the response should include UUIDs od connected clients.
* Defaults to `true`.
*/
fun hereNow(
channels: List = emptyList(),
channelGroups: List = emptyList(),
includeState: Boolean = false,
includeUUIDs: Boolean = true,
) = HereNowEndpoint(
pubnub = this,
channels = channels,
channelGroups = channelGroups,
includeState = includeState,
includeUUIDs = includeUUIDs,
)
/**
* Obtain information about the current list of channels to which a UUID is subscribed to.
*
* @param uuid UUID of the user to get its current channel subscriptions. Defaults to the UUID of the client.
* @see [BasePNConfiguration.uuid]
*/
fun whereNow(uuid: String = configuration.userId.value) = WhereNowEndpoint(pubnub = this, uuid = uuid)
/**
* Set state information specific to a subscriber UUID.
*
* State information is supplied as a JSON object of key/value pairs.
*
* If [BasePNConfiguration.maintainPresenceState] is `true`, and the `uuid` matches [BasePNConfiguration.uuid], the state
* for channels will be saved in the PubNub client and resent with every heartbeat and initial subscribe request.
* In that case, it's not recommended to mix setting state through channels *and* channel groups, as state set
* through the channel group will be overwritten after the next heartbeat or subscribe reconnection (e.g. after loss
* of network).
*
* @param channels Channels to set the state to.
* @param channelGroups Channel groups to set the state to.
* @param state The actual state object to set.
* NOTE: Presence state must be expressed as a JsonObject.
* When calling [PubNub.setPresenceState], be sure to supply an initialized JsonObject
* or POJO which can be serialized to a JsonObject.
* @param uuid UUID of the user to set the state for. Defaults to the UUID of the client.
* @see [PNConfiguration.uuid]
*/
fun setPresenceState(
channels: List = listOf(),
channelGroups: List = listOf(),
state: Any,
uuid: String = configuration.userId.value,
): SetStateEndpoint =
SetStateEndpoint(
pubnub = this,
channels = channels,
channelGroups = channelGroups,
state = state,
uuid = uuid,
presenceData = presenceData,
)
/**
* Retrieve state information specific to a subscriber UUID.
*
* State information is supplied as a JSON object of key/value pairs.
*
* @param channels Channels to get the state from.
* @param channelGroups Channel groups to get the state from.
* @param uuid UUID of the user to get the state from. Defaults to the UUID of the client.
* @see [PNConfiguration.uuid]
*/
fun getPresenceState(
channels: List = listOf(),
channelGroups: List = listOf(),
uuid: String = configuration.userId.value,
) = GetStateEndpoint(pubnub = this, channels = channels, channelGroups = channelGroups, uuid = uuid)
/**
* Track the online and offline status of users and devices in real time and store custom state information.
* When you have Presence enabled, PubNub automatically creates a presence channel for each channel.
*
* Subscribing to a presence channel or presence channel group will only return presence events
*
* @param channels Channels to subscribe/unsubscribe. Either `channel` or [channelGroups] are required.
* @param channelGroups Channel groups to subscribe/unsubscribe. Either `channelGroups` or [channels] are required.
*/
fun presence(
channels: List = emptyList(),
channelGroups: List = emptyList(),
connected: Boolean = false,
) = presence.presence(
channels = channels.toSet(),
channelGroups = channelGroups.toSet(),
connected = connected,
)
//endregion
//region MessageActions
/**
* Add an action on a published message. Returns the added action in the response.
*
* @param channel Channel to publish message actions to.
* @param messageAction The message action object containing the message action's type,
* value and the publish timetoken of the original message.
*/
fun addMessageAction(
channel: String,
messageAction: PNMessageAction,
) = AddMessageActionEndpoint(pubnub = this, channel = channel, messageAction = messageAction)
/**
* Remove a previously added action on a published message. Returns an empty response.
*
* @param channel Channel to remove message actions from.
* @param messageTimetoken The publish timetoken of the original message.
* @param actionTimetoken The publish timetoken of the message action to be removed.
*/
fun removeMessageAction(
channel: String,
messageTimetoken: Long,
actionTimetoken: Long,
) = RemoveMessageActionEndpoint(
pubnub = this,
channel = channel,
messageTimetoken = messageTimetoken,
actionTimetoken = actionTimetoken,
)
/**
* Get a list of message actions in a channel. Returns a list of actions in the response.
*
* @param channel Channel to fetch message actions from.
* @param start Message Action timetoken denoting the start of the range requested
* (return values will be less than start).
* @param end Message Action timetoken denoting the end of the range requested
* (return values will be greater than or equal to end).
* @param limit Specifies the number of message actions to return in response.
*/
@Deprecated(
replaceWith =
ReplaceWith(
"getMessageActions(channel = channel, page = PNBoundedPage(start = start, end = end, limit = limit))",
"com.pubnub.api.models.consumer.PNBoundedPage",
),
level = DeprecationLevel.WARNING,
message = "Use getMessageActions(String, PNBoundedPage) instead",
)
fun getMessageActions(
channel: String,
start: Long? = null,
end: Long? = null,
limit: Int? = null,
) = getMessageActions(channel = channel, page = PNBoundedPage(start = start, end = end, limit = limit))
/**
* Get a list of message actions in a channel. Returns a list of actions in the response.
*
* @param channel Channel to fetch message actions from.
* @param page The paging object used for pagination. @see [PNBoundedPage]
*/
fun getMessageActions(
channel: String,
page: PNBoundedPage = PNBoundedPage(),
) = GetMessageActionsEndpoint(pubnub = this, channel = channel, page = page)
//endregion
//region ChannelGroups
/**
* Adds a channel to a channel group.
*
* @param channels The channels to add to the channel group.
* @param channelGroup The channel group to add the channels to.
*/
fun addChannelsToChannelGroup(
channels: List,
channelGroup: String,
) = AddChannelChannelGroupEndpoint(pubnub = this, channels = channels, channelGroup = channelGroup)
/**
* Lists all the channels of the channel group.
*
* @param channelGroup Channel group to fetch the belonging channels.
*/
fun listChannelsForChannelGroup(channelGroup: String) = AllChannelsChannelGroupEndpoint(pubnub = this, channelGroup = channelGroup)
/**
* Removes channels from a channel group.
*
* @param channelGroup The channel group to remove channels from
* @param channels The channels to remove from the channel group.
*/
fun removeChannelsFromChannelGroup(
channels: List,
channelGroup: String,
) = RemoveChannelChannelGroupEndpoint(pubnub = this, channels = channels, channelGroup = channelGroup)
/**
* Lists all registered channel groups for the subscribe key.
*/
fun listAllChannelGroups() = ListAllChannelGroupEndpoint(this)
/**
* Removes the channel group.
*
* @param channelGroup The channel group to remove.
*/
fun deleteChannelGroup(channelGroup: String) = DeleteChannelGroupEndpoint(pubnub = this, channelGroup = channelGroup)
//endregion
//region PAM
/**
* This function establishes access permissions for PubNub Access Manager (PAM) by setting the `read` or `write`
* attribute to `true`.
* A grant with `read` or `write` set to `false` (or not included) will revoke any previous grants
* with `read` or `write` set to `true`.
*
* Permissions can be applied to any one of three levels:
* - Application level privileges are based on `subscribeKey` applying to all associated channels.
* - Channel level privileges are based on a combination of `subscribeKey` and `channel` name.
* - User level privileges are based on the combination of `subscribeKey`, `channel`, and `auth_key`.
*
* @param read Set to `true` to request the *read* permission. Defaults to `false`.
* @param write Set to `true` to request the *write* permission. Defaults to `false`.
* @param manage Set to `true` to request the *read* permission. Defaults to `false`.
* @param delete Set to `true` to request the *delete* permission. Defaults to `false`.
* @param ttl Time in minutes for which granted permissions are valid.
* Setting ttl to `0` will apply the grant indefinitely, which is also the default behavior.
*
* @param authKeys Specifies authKey to grant permissions to. It's possible to specify multiple auth keys.
* You can also grant access to a single authKey for multiple channels at the same time.
* @param channels Specifies the channels on which to grant permissions.
* If no channels/channelGroups are specified, then the grant applies to all channels/channelGroups
* that have been or will be created for that publish/subscribe key set.
*
* Furthermore, any existing or future grants on specific channels are ignored,
* until the all channels grant is revoked.
*
* It's possible to grant permissions to multiple channels simultaneously.
* Wildcard notation like a.* can be used to grant access on channels. You can grant one level deep.
* - `a.*` - you can grant on this.
* - `a.b.*` - grant won't work on this. If you grant on `a.b.*`,
* the grant will treat `a.b.*` as a single channel with name `a.b.*`.
* @param channelGroups Specifies the channel groups to grant permissions to.
* If no [channels] or [channelGroups] are specified, then the grant applies to all channels/channelGroups
* that have been or will be created for that publish/subscribe key set.
*
* Furthermore, any existing or future grants on specific [channelGroups] are ignored,
* until the all [channelGroups] grant is revoked.
*
* It's possible to grant permissions to multiple [channelGroups] simultaneously.
*/
fun grant(
read: Boolean = false,
write: Boolean = false,
manage: Boolean = false,
delete: Boolean = false,
ttl: Int = -1,
authKeys: List = emptyList(),
channels: List = emptyList(),
channelGroups: List = emptyList(),
uuids: List = emptyList(),
) = GrantEndpoint(
pubnub = this,
read = read,
write = write,
manage = manage,
delete = delete,
ttl = ttl,
authKeys = authKeys,
channels = channels,
channelGroups = channelGroups,
uuids = uuids,
)
/**
* See [grant]
*/
fun grant(
read: Boolean = false,
write: Boolean = false,
manage: Boolean = false,
delete: Boolean = false,
get: Boolean = false,
update: Boolean = false,
join: Boolean = false,
ttl: Int = -1,
authKeys: List = emptyList(),
channels: List = emptyList(),
channelGroups: List = emptyList(),
uuids: List = emptyList(),
) = GrantEndpoint(
pubnub = this,
read = read,
write = write,
manage = manage,
delete = delete,
get = get,
update = update,
join = join,
ttl = ttl,
authKeys = authKeys,
channels = channels,
channelGroups = channelGroups,
uuids = uuids,
)
/**
* This function generates a grant token for PubNub Access Manager (PAM).
*
* Permissions can be applied to any of the three type of resources:
* - channels
* - channel groups
* - uuid - metadata associated with particular UUID
*
* Each type of resource have different set of permissions. To know what's possible for each of them
* check ChannelGrant, ChannelGroupGrant and UUIDGrant.
*
* @param ttl Time in minutes for which granted permissions are valid.
* @param meta Additional metadata
* @param authorizedUUID Single uuid which is authorized to use the token to make API requests to PubNub
* @param channels List of all channel grants
* @param channelGroups List of all channel group grants
* @param uuids List of all uuid grants
*/
fun grantToken(
ttl: Int,
meta: Any? = null,
authorizedUUID: String? = null,
channels: List = emptyList(),
channelGroups: List = emptyList(),
uuids: List = emptyList(),
): GrantTokenEndpoint {
return GrantTokenEndpoint(
pubnub = this,
ttl = ttl,
meta = meta,
authorizedUUID = authorizedUUID,
channels = channels,
channelGroups = channelGroups,
uuids = uuids,
)
}
/**
* This function generates a grant token for PubNub Access Manager (PAM).
*
* Permissions can be applied to any of the two type of resources:
* - spacePermissions
* - userPermissions
*
* Each type of resource have different set of permissions. To know what's possible for each of them
* check SpacePermissions and UserPermissions.
*
* @param ttl Time in minutes for which granted permissions are valid.
* @param meta Additional metadata
* @param authorizedUserId Single userId which is authorized to use the token to make API requests to PubNub
* @param spacesPermissions List of all space grants
* @param usersPermissions List of all userId grants
*/
fun grantToken(
ttl: Int,
meta: Any? = null,
authorizedUserId: UserId? = null,
spacesPermissions: List = emptyList(),
usersPermissions: List = emptyList(),
): GrantTokenEndpoint {
return GrantTokenEndpoint(
pubnub = this,
ttl = ttl,
meta = meta,
authorizedUUID = authorizedUserId?.value,
channels = spacesPermissions.map { spacePermissions -> spacePermissions.toChannelGrant() },
channelGroups = emptyList(),
uuids = usersPermissions.map { userPermissions -> userPermissions.toUuidGrant() },
)
}
/**
* This method allows you to disable an existing token and revoke all permissions embedded within.
*
* @param token Existing token with embedded permissions.
*/
fun revokeToken(token: String): RevokeTokenEndpoint {
return RevokeTokenEndpoint(
pubnub = this,
token = token,
)
}
//endregion
//region Miscellaneous
/**
* Returns a 17 digit precision Unix epoch from the server.
*/
fun time() = TimeEndpoint(this)
//endregion
//region ObjectsAPI
/**
* Returns a paginated list of Channel Metadata objects, optionally including the custom data object for each.
*
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
*/
fun getAllChannelMetadata(
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
) = GetAllChannelMetadataEndpoint(
pubnub = this,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
includeQueryParam = IncludeQueryParam(includeCustom = includeCustom),
)
/**
* Returns metadata for the specified Channel, optionally including the custom data object for each.
*
* @param channel Channel name.
* @param includeCustom Include respective additional fields in the response.
*/
fun getChannelMetadata(
channel: String,
includeCustom: Boolean = false,
) = GetChannelMetadataEndpoint(
pubnub = this,
channel = channel,
includeQueryParam = IncludeQueryParam(includeCustom = includeCustom),
)
/**
* Set metadata for a Channel in the database, optionally including the custom data object for each.
*
* @param channel Channel name.
* @param name Name of a channel.
* @param description Description of a channel.
* @param custom Object with supported data types.
* @param includeCustom Include respective additional fields in the response.
*/
fun setChannelMetadata(
channel: String,
name: String? = null,
description: String? = null,
custom: Any? = null,
includeCustom: Boolean = false,
type: String? = null,
status: String? = null,
) = SetChannelMetadataEndpoint(
pubnub = this,
channel = channel,
name = name,
description = description,
custom = custom,
includeQueryParam = IncludeQueryParam(includeCustom = includeCustom),
type = type,
status = status,
)
/**
* Removes the metadata from a specified channel.
*
* @param channel Channel name.
*/
fun removeChannelMetadata(channel: String) = RemoveChannelMetadataEndpoint(this, channel = channel)
/**
* Returns a paginated list of UUID Metadata objects, optionally including the custom data object for each.
*
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
*/
fun getAllUUIDMetadata(
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
) = GetAllUUIDMetadataEndpoint(
pubnub = this,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
withInclude = IncludeQueryParam(includeCustom = includeCustom),
)
/**
* Returns metadata for the specified UUID, optionally including the custom data object for each.
*
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param includeCustom Include respective additional fields in the response.
*/
fun getUUIDMetadata(
uuid: String? = null,
includeCustom: Boolean = false,
) = GetUUIDMetadataEndpoint(
pubnub = this,
uuid = uuid ?: configuration.userId.value,
includeQueryParam = IncludeQueryParam(includeCustom = includeCustom),
)
/**
* Set metadata for a UUID in the database, optionally including the custom data object for each.
*
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param name Display name for the user. Maximum 200 characters.
* @param externalId User's identifier in an external system
* @param profileUrl The URL of the user's profile picture
* @param email The user's email address. Maximum 80 characters.
* @param custom Object with supported data types.
* @param includeCustom Include respective additional fields in the response.
*/
fun setUUIDMetadata(
uuid: String? = null,
name: String? = null,
externalId: String? = null,
profileUrl: String? = null,
email: String? = null,
custom: Any? = null,
includeCustom: Boolean = false,
type: String? = null,
status: String? = null,
) = SetUUIDMetadataEndpoint(
pubnub = this,
uuid = uuid,
name = name,
externalId = externalId,
profileUrl = profileUrl,
email = email,
custom = custom,
withInclude = IncludeQueryParam(includeCustom = includeCustom),
type = type,
status = status,
)
/**
* Removes the metadata from a specified UUID.
*
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
*/
fun removeUUIDMetadata(uuid: String? = null) = RemoveUUIDMetadataEndpoint(pubnub = this, uuid = uuid)
/**
* The method returns a list of channel memberships for a user. This method doesn't return a user's subscriptions.
*
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeChannelDetails Include custom fields for channels metadata.
*/
fun getMemberships(
uuid: String? = null,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeChannelDetails: PNChannelDetailsLevel? = null,
) = GetMembershipsEndpoint(
pubnub = this,
uuid = uuid ?: configuration.userId.value,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
includeQueryParam =
IncludeQueryParam(
includeCustom = includeCustom,
includeChannelDetails = includeChannelDetails,
includeType = false,
),
)
/**
* @see [PubNubCore.setMemberships]
*/
@Deprecated(
replaceWith =
ReplaceWith(
"setMemberships(channels = channels, uuid = uuid, limit = limit, " +
"page = page, filter = filter, sort = sort, includeCount = includeCount, includeCustom = includeCustom," +
"includeChannelDetails = includeChannelDetails)",
),
level = DeprecationLevel.WARNING,
message = "Use setMemberships instead",
)
fun addMemberships(
channels: List,
uuid: String? = null,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeChannelDetails: PNChannelDetailsLevel? = null,
) = setMemberships(
channels = channels,
uuid = uuid ?: configuration.userId.value,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeChannelDetails = includeChannelDetails,
)
/**
* Set channel memberships for a UUID.
*
* @param channels List of channels to add to membership. List can contain strings (channel-name only)
* or objects (which can include custom data). @see [PNChannelWithCustom]
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeChannelDetails Include custom fields for channels metadata.
*/
fun setMemberships(
channels: List,
uuid: String? = null,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeChannelDetails: PNChannelDetailsLevel? = null,
) = manageMemberships(
channelsToSet = channels,
channelsToRemove = listOf(),
uuid = uuid ?: configuration.userId.value,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeChannelDetails = includeChannelDetails,
)
/**
* Remove channel memberships for a UUID.
*
* @param channels Channels to remove from membership.
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeChannelDetails Include custom fields for channels metadata.
*/
fun removeMemberships(
channels: List,
uuid: String? = null,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeChannelDetails: PNChannelDetailsLevel? = null,
) = manageMemberships(
channelsToSet = listOf(),
channelsToRemove = channels,
uuid = uuid ?: configuration.userId.value,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeChannelDetails = includeChannelDetails,
)
/**
* Add and remove channel memberships for a UUID.
*
* @param channelsToSet Collection of channels to add to membership. @see [com.pubnub.api.models.consumer.objects.membership.PNChannelMembership.Partial]
* @param channelsToRemove Channels to remove from membership.
* @param uuid Unique user identifier. If not supplied then current user’s uuid is used.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeChannelDetails Include custom fields for channels metadata.
*/
fun manageMemberships(
channelsToSet: List,
channelsToRemove: List,
uuid: String? = null,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeChannelDetails: PNChannelDetailsLevel? = null,
) = ManageMembershipsEndpoint(
pubnub = this,
channelsToSet = channelsToSet,
channelsToRemove = channelsToRemove,
uuid = uuid ?: configuration.userId.value,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
includeQueryParam =
IncludeQueryParam(
includeCustom = includeCustom,
includeChannelDetails = includeChannelDetails,
includeType = false,
),
)
/**
* @see [PubNub.getChannelMembers]
*/
@Deprecated(
replaceWith =
ReplaceWith(
"getChannelMembers(channel = channel, limit = limit, " +
"page = page, filter = filter, sort = sort, includeCount = includeCount, includeCustom = includeCustom," +
"includeUUIDDetails = includeUUIDDetails)",
),
level = DeprecationLevel.WARNING,
message = "Use getChannelMembers instead",
)
fun getMembers(
channel: String,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = getChannelMembers(
channel = channel,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
)
/**
* The method returns a list of members in a channel. The list will include user metadata for members
* that have additional metadata stored in the database.
*
* @param channel Channel name
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeUUIDDetails Include custom fields for UUIDs metadata.
*/
fun getChannelMembers(
channel: String,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = GetChannelMembersEndpoint(
pubnub = this,
channel = channel,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
includeQueryParam =
IncludeQueryParam(
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
includeType = false,
),
)
/**
* @see [PubNub.setChannelMembers]
*/
@Deprecated(
replaceWith =
ReplaceWith(
"setChannelMembers(channel = channel, uuids = uuids, limit = limit, " +
"page = page, filter = filter, sort = sort, includeCount = includeCount, includeCustom = includeCustom," +
"includeUUIDDetails = includeUUIDDetails)",
),
level = DeprecationLevel.WARNING,
message = "Use setChannelMembers instead",
)
fun addMembers(
channel: String,
uuids: List,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = setChannelMembers(
channel = channel,
uuids = uuids,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
)
/**
* This method sets members in a channel.
*
* @param channel Channel name
* @param uuids List of members to add to the channel. List can contain strings (uuid only)
* or objects (which can include custom data). @see [PNMember.Partial]
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeUUIDDetails Include custom fields for UUIDs metadata.
*/
fun setChannelMembers(
channel: String,
uuids: List,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = manageChannelMembers(
channel = channel,
uuidsToSet = uuids,
uuidsToRemove = listOf(),
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
)
/**
* @see [PubNub.removeChannelMembers]
*/
@Deprecated(
replaceWith =
ReplaceWith(
"removeChannelMembers(channel = channel, uuids = uuids, limit = limit, " +
"page = page, filter = filter, sort = sort, includeCount = includeCount, includeCustom = includeCustom," +
"includeUUIDDetails = includeUUIDDetails)",
),
level = DeprecationLevel.WARNING,
message = "Use removeChannelMembers instead",
)
fun removeMembers(
channel: String,
uuids: List,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = removeChannelMembers(
channel = channel,
uuids = uuids,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
)
/**
* Remove members from a Channel.
*
* @param channel Channel name
* @param uuids Members to remove from channel.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeUUIDDetails Include custom fields for UUIDs metadata.
*/
fun removeChannelMembers(
channel: String,
uuids: List,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = manageChannelMembers(
channel = channel,
uuidsToSet = listOf(),
uuidsToRemove = uuids,
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
)
/**
* Set or remove members in a channel.
*
* @param channel Channel name
* @param uuidsToSet Collection of members to add to the channel. @see [com.pubnub.api.models.consumer.objects.member.PNMember.Partial]
* @param uuidsToRemove Members to remove from channel.
* @param limit Number of objects to return in the response.
* Default is 100, which is also the maximum value.
* Set limit to 0 (zero) and includeCount to true if you want to retrieve only a result count.
* @param page Use for pagination.
* - [PNNext] : Previously-returned cursor bookmark for fetching the next page.
* - [PNPrev] : Previously-returned cursor bookmark for fetching the previous page.
* Ignored if you also supply the start parameter.
* @param filter Expression used to filter the results. Only objects whose properties satisfy the given
* expression are returned.
* @param sort List of properties to sort by. Available options are id, name, and updated.
* @see [PNAsc], [PNDesc]
* @param includeCount Request totalCount to be included in paginated response. By default, totalCount is omitted.
* Default is `false`.
* @param includeCustom Include respective additional fields in the response.
* @param includeUUIDDetails Include custom fields for UUIDs metadata.
*/
fun manageChannelMembers(
channel: String,
uuidsToSet: Collection,
uuidsToRemove: Collection,
limit: Int? = null,
page: PNPage? = null,
filter: String? = null,
sort: Collection> = listOf(),
includeCount: Boolean = false,
includeCustom: Boolean = false,
includeUUIDDetails: PNUUIDDetailsLevel? = null,
) = ManageChannelMembersEndpoint(
pubnub = this,
channel = channel,
uuidsToSet = uuidsToSet,
uuidsToRemove = uuidsToRemove,
collectionQueryParameters =
CollectionQueryParameters(
limit = limit,
page = page,
filter = filter,
sort = sort,
includeCount = includeCount,
),
includeQueryParam =
IncludeQueryParam(
includeCustom = includeCustom,
includeUUIDDetails = includeUUIDDetails,
includeType = false,
),
)
//endregion ObjectsAPI
//region files
/**
* Upload file / data to specified Channel.
*
* @param channel Channel name
* @param fileName Name of the file to send.
* @param inputStream Input stream with file content. The inputStream will be depleted after the call.
* @param message The payload.
* **Warning:** It is important to note that you should not serialize JSON
* when sending signals/messages via PubNub.
* Why? Because the serialization is done for you automatically.
* Instead just pass the full object as the message payload.
* PubNub takes care of everything for you.
* @param meta Metadata object which can be used with the filtering ability.
* @param ttl Set a per message time to live in storage.
* - If `shouldStore = true`, and `ttl = 0`, the message is stored
* with no expiry time.
* - If `shouldStore = true` and `ttl = X` (`X` is an Integer value),
* the message is stored with an expiry time of `X` hours.
* - If `shouldStore = false`, the `ttl` parameter is ignored.
* - If ttl isn't specified, then expiration of the message defaults
* back to the expiry value for the key.
* @param shouldStore Store in history.
* If not specified, then the history configuration of the key is used.
* @param cipherKey Key to be used to encrypt uploaded data.
*/
fun sendFile(
channel: String,
fileName: String,
inputStream: InputStream,
message: Any? = null,
meta: Any? = null,
ttl: Int? = null,
shouldStore: Boolean? = null,
cipherKey: String? = null,
): SendFileEndpoint {
val cryptoModule =
if (cipherKey != null) {
CryptoModule.createLegacyCryptoModule(cipherKey)
} else {
configuration.cryptoModule
}
return SendFileEndpoint(
channel = channel,
fileName = fileName,
inputStream = inputStream,
message = message,
meta = meta,
ttl = ttl,
shouldStore = shouldStore,
executorService =
retrofitManager.getTransactionClientExecutorService()
?: Executors.newSingleThreadExecutor(),
fileMessagePublishRetryLimit = configuration.fileMessagePublishRetryLimit,
generateUploadUrlFactory = GenerateUploadUrlEndpoint.Factory(this),
publishFileMessageFactory = PublishFileMessageEndpoint.Factory(this),
sendFileToS3Factory = UploadFileEndpoint.Factory(this),
cryptoModule = cryptoModule,
)
}
/**
* Retrieve list of files uploaded to Channel.
*
* @param channel Channel name
* @param limit Number of files to return. Minimum value is 1, and maximum is 100. Default value is 100.
* @param next Previously-returned cursor bookmark for fetching the next page. @see [PNPage.PNNext]
*/
fun listFiles(
channel: String,
limit: Int? = null,
next: PNPage.PNNext? = null,
): ListFilesEndpoint {
return ListFilesEndpoint(
pubNub = this,
channel = channel,
limit = limit,
next = next,
)
}
/**
* Generate URL which can be used to download file from target Channel.
*
* @param channel Name of channel to which the file has been uploaded.
* @param fileName Name under which the uploaded file is stored.
* @param fileId Unique identifier for the file, assigned during upload.
*/
fun getFileUrl(
channel: String,
fileName: String,
fileId: String,
): GetFileUrlEndpoint {
return GetFileUrlEndpoint(
pubNub = this,
channel = channel,
fileName = fileName,
fileId = fileId,
)
}
/**
* Download file from specified Channel.
*
* @param channel Name of channel to which the file has been uploaded.
* @param fileName Name under which the uploaded file is stored.
* @param fileId Unique identifier for the file, assigned during upload.
* @param cipherKey Key to be used to decrypt downloaded data. If a key is not provided,
* the SDK uses the cipherKey from the @see [PNConfiguration].
*/
fun downloadFile(
channel: String,
fileName: String,
fileId: String,
cipherKey: String? = null,
): DownloadFileEndpoint {
val cryptoModule =
if (cipherKey != null) {
CryptoModule.createLegacyCryptoModule(cipherKey)
} else {
configuration.cryptoModule
}
return DownloadFileEndpoint(
pubNub = this,
channel = channel,
fileName = fileName,
fileId = fileId,
cryptoModule = cryptoModule,
)
}
/**
* Delete file from specified Channel.
*
* @param channel Name of channel to which the file has been uploaded.
* @param fileName Name under which the uploaded file is stored.
* @param fileId Unique identifier for the file, assigned during upload.
*/
fun deleteFile(
channel: String,
fileName: String,
fileId: String,
): DeleteFileEndpoint {
return DeleteFileEndpoint(
pubNub = this,
channel = channel,
fileName = fileName,
fileId = fileId,
)
}
/**
* Publish file message from specified Channel.
* @param channel Name of channel to which the file has been uploaded.
* @param fileName Name under which the uploaded file is stored.
* @param fileId Unique identifier for the file, assigned during upload.
* @param message The payload.
* **Warning:** It is important to note that you should not serialize JSON
* when sending signals/messages via PubNub.
* Why? Because the serialization is done for you automatically.
* Instead just pass the full object as the message payload.
* PubNub takes care of everything for you.
* @param meta Metadata object which can be used with the filtering ability.
* @param ttl Set a per message time to live in storage.
* - If `shouldStore = true`, and `ttl = 0`, the message is stored
* with no expiry time.
* - If `shouldStore = true` and `ttl = X` (`X` is an Integer value),
* the message is stored with an expiry time of `X` hours.
* - If `shouldStore = false`, the `ttl` parameter is ignored.
* - If ttl isn't specified, then expiration of the message defaults
* back to the expiry value for the key.
* @param shouldStore Store in history.
* If not specified, then the history configuration of the key is used.
*
*/
fun publishFileMessage(
channel: String,
fileName: String,
fileId: String,
message: Any? = null,
meta: Any? = null,
ttl: Int? = null,
shouldStore: Boolean? = null,
): PublishFileMessageEndpoint {
return PublishFileMessageEndpoint(
pubNub = this,
channel = channel,
fileName = fileName,
fileId = fileId,
message = message,
meta = meta,
ttl = ttl,
shouldStore = shouldStore,
)
}
//endregion
//region Encryption
/**
* Perform Cryptographic decryption of an input string using cipher key provided by [BasePNConfiguration.cipherKey].
*
* @param inputString String to be decrypted.
*
* @return String containing the decryption of `inputString` using `cipherKey`.
* @throws PubNubException throws exception in case of failed decryption.
*/
@Throws(PubNubException::class)
fun decrypt(inputString: String): String = decrypt(inputString, null)
/**
* Perform Cryptographic decryption of an input string using a cipher key.
*
* @param inputString String to be decrypted.
* @param cipherKey cipher key to be used for decryption. Default is [BasePNConfiguration.cipherKey]
*
* @return String containing the decryption of `inputString` using `cipherKey`.
* @throws PubNubException throws exception in case of failed decryption.
*/
@Throws(PubNubException::class)
fun decrypt(
inputString: String,
cryptoModule: CryptoModule? = null,
): String = getCryptoModuleOrThrow(cryptoModule).decryptString(inputString)
/**
* Perform Cryptographic decryption of an input stream using provided cipher key.
*
* @param inputStream InputStream to be encrypted.
* @param cipherKey Cipher key to be used for decryption.
*
* @return InputStream containing the encryption of `inputStream` using `cipherKey`.
* @throws PubNubException Throws exception in case of failed decryption.
*/
@Throws(PubNubException::class)
fun decryptInputStream(
inputStream: InputStream,
cryptoModule: CryptoModule? = null,
): InputStream = getCryptoModuleOrThrow(cryptoModule).decryptStream(inputStream)
/**
* Perform Cryptographic encryption of an input string and a cipher key.
*
* @param inputString String to be encrypted.
* @param cipherKey Cipher key to be used for encryption. Default is [BasePNConfiguration.cipherKey]
*
* @return String containing the encryption of `inputString` using `cipherKey`.
* @throws PubNubException Throws exception in case of failed encryption.
*/
@Throws(PubNubException::class)
fun encrypt(
inputString: String,
cryptoModule: CryptoModule? = null,
): String = getCryptoModuleOrThrow(cryptoModule).encryptString(inputString)
/**
* Perform Cryptographic encryption of an input stream using provided cipher key.
*
* @param inputStream InputStream to be encrypted.
* @param cipherKey Cipher key to be used for encryption.
*
* @return InputStream containing the encryption of `inputStream` using `cipherKey`.
* @throws PubNubException Throws exception in case of failed encryption.
*/
@Throws(PubNubException::class)
fun encryptInputStream(
inputStream: InputStream,
cryptoModule: CryptoModule? = null,
): InputStream = getCryptoModuleOrThrow(cryptoModule).encryptStream(inputStream)
@Throws(PubNubException::class)
private fun getCryptoModuleOrThrow(cryptoModule: CryptoModule? = null): CryptoModule {
return cryptoModule ?: configuration.cryptoModule ?: throw PubNubException("Crypto module is not initialized")
}
//endregion
/**
* Force the SDK to try and reach out PubNub. Monitor the results in [SubscribeCallback.status]
*
* @param timetoken optional timetoken to use for the subscriptions on reconnection.
*/
fun reconnect(timetoken: Long = 0L) {
subscribe.reconnect(timetoken)
presence.reconnect()
}
/**
* Cancel any subscribe and heartbeat loops or ongoing re-connections.
*
* Monitor the results in [SubscribeCallback.status]
*/
fun disconnect() {
subscribe.disconnect()
presence.disconnect()
}
/**
* Frees up threads and allows for a clean exit.
*/
fun destroy() {
subscribe.destroy()
presence.destroy()
retrofitManager.destroy()
executorService.shutdown()
}
/**
* Same as [destroy] but immediately.
*/
fun forceDestroy() {
subscribe.destroy()
presence.destroy()
retrofitManager.destroy(true)
executorService.shutdownNow()
}
fun parseToken(token: String): PNToken {
return tokenParser.unwrapToken(token)
}
fun setToken(token: String?) {
return tokenManager.setToken(token)
}
// internal
private val lockChannelsAndGroups = Any()
private val channelSubscriptions = mutableMapOf>>()
private val channelGroupSubscriptions = mutableMapOf>>()
internal fun subscribe(
vararg subscriptions: BaseSubscriptionImpl<*>,
cursor: SubscriptionCursor,
) {
synchronized(lockChannelsAndGroups) {
val channelsToSubscribe = mutableSetOf()
subscriptions.forEach { subscription ->
subscription.channels.forEach { channelName ->
channelSubscriptions.computeIfAbsent(channelName) { mutableSetOf() }
.also { set -> set.add(subscription) }
channelsToSubscribe.add(channelName)
}
}
val groupsToSubscribe = mutableSetOf()
subscriptions.forEach { subscription ->
subscription.channelGroups.forEach { channelGroupName ->
channelGroupSubscriptions.computeIfAbsent(channelGroupName) { mutableSetOf() }
.also { set -> set.add(subscription) }
groupsToSubscribe.add(channelGroupName)
}
}
val (channelsWithPresence, channelsNoPresence) =
channelsToSubscribe.filter { !it.isPresence }
.partition {
channelsToSubscribe.contains(it.withPresence)
}
val (groupsWithPresence, groupsNoPresence) =
groupsToSubscribe.filter { !it.isPresence }.partition {
groupsToSubscribe.contains(it.withPresence)
}
if (channelsWithPresence.isNotEmpty() || groupsWithPresence.isNotEmpty()) {
subscribeInternal(
channels = channelsWithPresence.map(ChannelName::id),
channelGroups = groupsWithPresence.map(ChannelGroupName::id),
withPresence = true,
withTimetoken = cursor.timetoken,
)
}
if (channelsNoPresence.isNotEmpty() || groupsNoPresence.isNotEmpty()) {
subscribeInternal(
channels = channelsNoPresence.map(ChannelName::id),
channelGroups = groupsNoPresence.map(ChannelGroupName::id),
withPresence = false,
withTimetoken = cursor.timetoken,
)
}
}
}
internal fun unsubscribe(vararg subscriptions: BaseSubscriptionImpl<*>) {
synchronized(lockChannelsAndGroups) {
val channelsToUnsubscribe = mutableSetOf()
subscriptions.forEach { subscription ->
subscription.channels.forEach { channelName ->
val set = channelSubscriptions[channelName]
set?.remove(subscription)
if (set != null && set.isEmpty()) { // there were mappings but there none now
channelsToUnsubscribe += channelName
channelSubscriptions.remove(channelName)
}
}
}
val groupsToUnsubscribe = mutableSetOf()
subscriptions.forEach { subscription ->
subscription.channelGroups.forEach { channelGroupName ->
val set = channelGroupSubscriptions[channelGroupName]
set?.remove(subscription)
if (set != null && set.isEmpty()) {
groupsToUnsubscribe += channelGroupName
channelGroupSubscriptions.remove(channelGroupName)
}
}
}
if (channelsToUnsubscribe.isNotEmpty() || groupsToUnsubscribe.isNotEmpty()) {
unsubscribeInternal(
channels = channelsToUnsubscribe.map(ChannelName::id),
channelGroups = groupsToUnsubscribe.map(ChannelGroupName::id),
)
}
}
}
private val channelSubscriptionMap = mutableMapOf>()
private val channelGroupSubscriptionMap = mutableMapOf>()
//region Subscribe
/**
* Causes the client to create an open TCP socket to the PubNub Real-Time Network and begin listening for messages
* on a specified channel.
*
* To subscribe to a channel the client must send the appropriate [BasePNConfiguration.subscribeKey] at initialization.
*
* By default, a newly subscribed client will only receive messages published to the channel
* after the `subscribe()` call completes.
*
* If a client gets disconnected from a channel, it can automatically attempt to reconnect to that channel
* and retrieve any available messages that were missed during that period.
* This can be achieved by setting [BasePNConfiguration.retryConfiguration] when
* initializing the client.
*
* @param channels Channels to subscribe/unsubscribe. Either `channel` or [channelGroups] are required.
* @param channelGroups Channel groups to subscribe/unsubscribe. Either `channelGroups` or [channels] are required.
* @param withPresence Also subscribe to related presence channel.
* @param withTimetoken A timetoken to start the subscribe loop from.
*/
@Synchronized
fun subscribe(
channels: List = emptyList(),
channelGroups: List = emptyList(),
withPresence: Boolean = false,
withTimetoken: Long = 0L,
) {
val toSubscribe = mutableSetOf>()
channels.filter { it.isNotEmpty() }.map { ChannelName(it) }.forEach { channelName ->
// if we are adding a NEW subscriptions in this step, this var will contain it:
var subscription: BaseSubscriptionImpl<*>? = null
channelSubscriptionMap.computeIfAbsent(channelName) { newChannelName ->
val channel =
BaseChannelImpl(
this,
newChannelName,
subscriptionFactory,
)
val options =
if (withPresence) {
SubscriptionOptions.receivePresenceEvents()
} else {
EmptyOptions
}
channel.subscription(options).also { sub ->
toSubscribe.add(sub)
subscription = sub
}
}
// make sure we are also subscribed and tracking the -pnpres channel if withPresence==true
if (withPresence) {
channelSubscriptionMap.computeIfAbsent(channelName.withPresence) { presenceChannelName ->
// this will either be the subscriptions we just created in the previous step,
// or if we were already subscribed to the channel WITHOUT presence, we need to create a new one
subscription ?: BaseChannelImpl(
this,
presenceChannelName,
subscriptionFactory,
).subscription().also { sub ->
toSubscribe.add(sub)
}
}
}
}
channelGroups.filter { it.isNotEmpty() }.map { ChannelGroupName(it) }.forEach { channelGroupName ->
var subscription: BaseSubscriptionImpl<*>? = null
channelGroupSubscriptionMap.computeIfAbsent(channelGroupName) { newChannelGroupName ->
val channelGroup = BaseChannelGroupImpl(this, newChannelGroupName, subscriptionFactory)
val options =
if (withPresence) {
SubscriptionOptions.receivePresenceEvents()
} else {
EmptyOptions
}
channelGroup.subscription(options).also { sub ->
toSubscribe.add(sub)
subscription = sub
}
}
// make sure we are also subscribed and tracking the -pnpres channel if withPresence==true
if (withPresence) {
channelGroupSubscriptionMap.computeIfAbsent(channelGroupName.withPresence) { presenceGroupName ->
// this will either be the subscriptions we just created in the previous step,
// or if we were already subscribed to the channel WITHOUT presence, we need to create a new one
subscription ?: BaseChannelGroupImpl(this, presenceGroupName, subscriptionFactory)
.subscription().also { sub ->
toSubscribe.add(sub)
}
}
}
}
// actually subscribe to all subscriptions created in this function and added to the set
subscribe(*toSubscribe.toTypedArray(), cursor = SubscriptionCursor(withTimetoken))
}
/**
* When subscribed to a single channel, this function causes the client to issue a leave from the channel
* and close any open socket to the PubNub Network.
*
* For multiplexed channels, the specified channel(s) will be removed and the socket remains open
* until there are no more channels remaining in the list.
*
* * **WARNING**
* Unsubscribing from all the channel(s) and then subscribing to a new channel Y isn't the same as
* Subscribing to channel Y and then unsubscribing from the previously subscribed channel(s).
*
* Unsubscribing from all the channels resets the timetoken and thus,
* there could be some gaps in the subscriptions that may lead to a message loss.
*
* @param channels Channels to subscribe/unsubscribe. Either `channel` or [channelGroups] are required.
* @param channelGroups Channel groups to subscribe/unsubscribe. Either `channelGroups` or [channels] are required.
*/
@Synchronized
fun unsubscribe(
channels: List = emptyList(),
channelGroups: List = emptyList(),
) {
val toUnsubscribe: MutableSet> = mutableSetOf()
channels.filter { it.isNotEmpty() }.map { ChannelName(it) }.forEach { channelName ->
channelSubscriptionMap.remove(channelName)?.let { sub ->
toUnsubscribe.add(sub)
}
channelSubscriptionMap.remove(channelName.withPresence)?.let { sub ->
toUnsubscribe.add(sub)
}
}
channelGroups.filter { it.isNotEmpty() }.map { ChannelGroupName(it) }.forEach { groupName ->
channelGroupSubscriptionMap.remove(groupName)?.let { sub ->
toUnsubscribe.add(sub)
}
channelGroupSubscriptionMap.remove(groupName.withPresence)?.let { sub ->
toUnsubscribe.add(sub)
}
}
unsubscribe(*toUnsubscribe.toTypedArray())
}
}