diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8216430a..0c2c7136 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] nexus = "2.0.0" -kotlin = "2.0.10" +kotlin = "2.0.20" vanniktech = "0.29.0" ktlint = "12.1.0" dokka = "1.9.20" @@ -20,7 +20,6 @@ pubnub-kotlin-test = { module = "com.pubnub:pubnub-kotlin-test", version.ref = " #jetbrains-annotations = { module = "org.jetbrains:annotations", version = "24.1.0" } kotlinx-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu", version = "0.25.0" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx_serialization" } -benasher44-uuid = { module = "com.benasher44:uuid", version = "0.8.4" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx_datetime"} lighthousegames-logging = { module = "org.lighthousegames:logging", version = "1.5.0"} @@ -40,4 +39,4 @@ benmanes-versions = { id = "com.github.ben-manes.versions", version = "0.42.0" } vanniktech-maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktech" } gradle-nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" } kotlinx-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.16.2" } -mokkery = { id = "dev.mokkery", version = "2.2.0" } +mokkery = { id = "dev.mokkery", version = "2.3.0" } diff --git a/pubnub-chat-impl/build.gradle.kts b/pubnub-chat-impl/build.gradle.kts index 8e68bebb..ed039a02 100644 --- a/pubnub-chat-impl/build.gradle.kts +++ b/pubnub-chat-impl/build.gradle.kts @@ -22,7 +22,6 @@ kotlin { implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.atomicfu) - implementation(libs.benasher44.uuid) implementation(libs.lighthousegames.logging) } } diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt index 14d0a50e..6e2f946a 100644 --- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt +++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/ChatImpl.kt @@ -1,6 +1,5 @@ package com.pubnub.chat.internal -import com.benasher44.uuid.uuid4 import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.asMap @@ -121,6 +120,8 @@ import org.lighthousegames.logging.KmLogging import org.lighthousegames.logging.logging import kotlin.reflect.KClass import kotlin.time.Duration.Companion.seconds +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid class ChatImpl( override val config: ChatConfiguration, @@ -456,6 +457,7 @@ class ChatImpl( } } + @OptIn(ExperimentalUuidApi::class) override fun createPublicConversation( channelId: String?, channelName: String?, @@ -463,7 +465,7 @@ class ChatImpl( channelCustom: CustomObject?, channelStatus: String? ): PNFuture { - val finalChannelId: String = channelId ?: uuid4().toString() + val finalChannelId: String = channelId ?: Uuid.random().toString() return createChannel( id = finalChannelId, @@ -523,6 +525,7 @@ class ChatImpl( } } + @OptIn(ExperimentalUuidApi::class) override fun createGroupConversation( invitedUsers: Collection, channelId: String?, @@ -533,7 +536,7 @@ class ChatImpl( membershipCustom: CustomObject? ): PNFuture { val user = this.currentUser - val finalChannelId = channelId ?: uuid4().toString() + val finalChannelId = channelId ?: Uuid.random().toString() return getChannel(finalChannelId).thenAsync { channel -> channel?.asFuture() ?: createChannel( finalChannelId, @@ -587,31 +590,38 @@ class ChatImpl( callback: (event: Event) -> Unit ): AutoCloseable { val handler = fun(_: PubNub, pnEvent: PNEvent) { - if (pnEvent.channel != channelId) { - return - } - val message = (pnEvent as? MessageResult)?.message ?: return - val eventContent: EventContent = try { - PNDataEncoder.decode(message) - } catch (e: Exception) { - if (message.asMap()?.get("type")?.asString() == "custom") { - EventContent.Custom((message.decode() as Map) - "type") - } else { - throw e + try { + if (pnEvent.channel != channelId) { + return + } + val message = (pnEvent as? MessageResult)?.message ?: return + val eventContent: EventContent = try { + PNDataEncoder.decode(message) + } catch (e: Exception) { + if (message.asMap()?.get("type")?.asString() == "custom") { + EventContent.Custom((message.decode() as Map) - "type") + } else { + throw e + } } - } - @Suppress("UNCHECKED_CAST") - val payload = eventContent as? T ?: return + val payload: T = if (type.isInstance(eventContent)) { + eventContent as T + } else { + return + } - val event = EventImpl( - chat = this, - timetoken = pnEvent.timetoken!!, // todo can this even be null? - payload = payload, - channelId = pnEvent.channel, - userId = pnEvent.publisher!! // todo can this even be null? - ) - callback(event) + val event = EventImpl( + chat = this, + timetoken = pnEvent.timetoken!!, // todo can this even be null? + payload = payload, + channelId = pnEvent.channel, + userId = pnEvent.publisher!! // todo can this even be null? + ) + callback(event) + } catch (e: Exception) { + log.e(e, msg = { e.message }) + } } val method = type.getEmitMethod() ?: customMethod val listener = createEventListener( diff --git a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt index 6bb097a3..02cf06e9 100644 --- a/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt +++ b/pubnub-chat-impl/src/commonMain/kotlin/com/pubnub/chat/internal/channel/BaseChannel.kt @@ -51,7 +51,6 @@ import com.pubnub.chat.internal.error.PubNubErrorMessage.MODERATION_CAN_BE_SET_O import com.pubnub.chat.internal.error.PubNubErrorMessage.READ_RECEIPTS_ARE_NOT_SUPPORTED_IN_PUBLIC_CHATS import com.pubnub.chat.internal.error.PubNubErrorMessage.THREAD_CHANNEL_DOES_NOT_EXISTS import com.pubnub.chat.internal.error.PubNubErrorMessage.TYPING_INDICATORS_NO_SUPPORTED_IN_PUBLIC_CHATS -import com.pubnub.chat.internal.error.PubNubErrorMessage.UNABLE_TO_READ_MESSAGES import com.pubnub.chat.internal.message.BaseMessage import com.pubnub.chat.internal.message.MessageImpl import com.pubnub.chat.internal.restrictions.RestrictionImpl @@ -99,7 +98,7 @@ import tryLong import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds -internal const val CANNOT_QUOTE_MESSAGE_FROM_OTHER_CHANNELS = "You cannot quote messages from other channels" +private const val CANNOT_QUOTE_MESSAGE_FROM_OTHER_CHANNELS = "You cannot quote messages from other channels" abstract class BaseChannel( override val chat: ChatInternal, @@ -195,7 +194,7 @@ abstract class BaseChannel( if (isTyping) { runWithDelay(typingTimeout + 10.milliseconds) { // +10ms just to make sure the timeout expires typingIndicatorsLock.withLock { - removeExpiredTypingIndicators(typingTimeout, typingIndicators, now) + removeExpiredTypingIndicators(typingTimeout, typingIndicators, clock.now()) typingIndicators.keys.toList() }.also { typingIndicatorsList -> callback(typingIndicatorsList) @@ -731,7 +730,7 @@ abstract class BaseChannel( HistoryResponse( messages = pnFetchMessagesResult.channelsUrlDecoded[channelId]?.map { messageItem: PNFetchMessageItem -> messageFactory(chat, messageItem, channelId) - } ?: log.pnError(UNABLE_TO_READ_MESSAGES), + } ?: emptyList(), isMore = pnFetchMessagesResult.channelsUrlDecoded[channelId]?.size == count ) }.catch { diff --git a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt index d924441d..95ac006a 100644 --- a/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt +++ b/pubnub-chat-impl/src/commonTest/kotlin/com/pubnub/kmp/ChatTest.kt @@ -1,6 +1,5 @@ package com.pubnub.kmp -import com.benasher44.uuid.uuid4 import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.UserId @@ -80,6 +79,8 @@ import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.time.Duration.Companion.milliseconds +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid class ChatTest : BaseTest() { private lateinit var objectUnderTest: ChatImpl @@ -1192,6 +1193,7 @@ class ChatTest : BaseTest() { } } + @OptIn(ExperimentalUuidApi::class) @Test fun whenCreatingPublicConversationWithoutChannelIdShouldGenerateIt() { every { pubnub.getChannelMetadata(any()) } returns getChannelMetadataEndpoint @@ -1213,7 +1215,7 @@ class ChatTest : BaseTest() { callback1.accept( Result.success( getPNChannelMetadataResult( - uuid4().toString(), + Uuid.random().toString(), name, description, customData,