Skip to content

Commit

Permalink
MTSDK-197 Enhance resilience.
Browse files Browse the repository at this point in the history
- Improve resilience of Transport SDK during parsing of unknown types of StructureMessage.
- Improve resilience of History fetch api.
  • Loading branch information
AfanasievAnton committed Jun 29, 2023
1 parent 2560b48 commit d684a64
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 24 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ plugins {
}

// CocoaPods requires the podspec to have a `version`.
val buildVersion = "2.4.0"
val buildVersion = "2.4.1"
val snapshot = System.getenv("SNAPSHOT_BUILD") ?: ""
version = "${buildVersion}${snapshot}"
group = "cloud.genesys"
Expand Down
8 changes: 4 additions & 4 deletions iosApp/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- transport (2.4.0)
- transport (2.4.1)

DEPENDENCIES:
- transport (from `../transport`)
Expand All @@ -9,8 +9,8 @@ EXTERNAL SOURCES:
:path: "../transport"

SPEC CHECKSUMS:
transport: 33995ef29d337fba19cc174784749b37ed2e6845
transport: 0068e821988a5eb502bc2a39ed2d0d66d9df0fd3

PODFILE CHECKSUM: c3105f0698090ba6d9702820eb0f13f123776417
PODFILE CHECKSUM: 10743e43aeaf72bb49673a0e57360c028906ace5

COCOAPODS: 1.11.3
COCOAPODS: 1.12.1
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal class ErrorCodeTest {
assertTrue(ErrorCode.mapFrom(6001) is ErrorCode.AuthFailed)
assertTrue(ErrorCode.mapFrom(6002) is ErrorCode.AuthLogoutFailed)
assertTrue(ErrorCode.mapFrom(6003) is ErrorCode.RefreshAuthTokenFailure)
assertTrue(ErrorCode.mapFrom(6004) is ErrorCode.HistoryFetchFailure)
val randomIn300Range = Random.nextInt(300, 400)
assertEquals(
ErrorCode.mapFrom(randomIn300Range),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal class MessageExtensionTest {
from = Message.Participant(originatingEntity = Message.Participant.OriginatingEntity.Human),
)

val result = TestWebMessagingApiResponses.testMessageEntityList.toMessageList()
val result = TestWebMessagingApiResponses.testMessageEntityList.entities.toMessageList()

assertThat(result).containsExactly(expectedMessage1, expectedMessage2)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class MessagingClientImplTest {
any(),
any()
)
} returns TestWebMessagingApiResponses.testMessageEntityList
} returns Result.Success(TestWebMessagingApiResponses.testMessageEntityList)
}

private val mockReconnectionHandler: ReconnectionHandlerImpl = mockk(relaxed = true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ sealed class ErrorCode(val code: Int) {
object AuthFailed : ErrorCode(6001)
object AuthLogoutFailed : ErrorCode(6002)
object RefreshAuthTokenFailure : ErrorCode(6003)
object HistoryFetchFailure : ErrorCode(6004)
data class RedirectResponseError(val value: Int) : ErrorCode(value)
data class ClientResponseError(val value: Int) : ErrorCode(value)
data class ServerResponseError(val value: Int) : ErrorCode(value)
Expand Down Expand Up @@ -57,6 +58,7 @@ sealed class ErrorCode(val code: Int) {
6001 -> AuthFailed
6002 -> AuthLogoutFailed
6003 -> RefreshAuthTokenFailure
6004 -> HistoryFetchFailure
in 300..399 -> RedirectResponseError(value)
in 400..499 -> ClientResponseError(value)
in 500..599 -> ServerResponseError(value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,26 @@ internal class MessagingClientImpl(
return
}
log.i { "fetching history for page index = ${messageStore.nextPage}" }
jwtHandler.withJwt { jwt -> api.getMessages(jwt, messageStore.nextPage) }
.also {
messageStore.updateMessageHistory(
it.toMessageList(),
it.total,
)
jwtHandler.withJwt { jwt ->
api.getMessages(jwt, messageStore.nextPage).also {
when (it) {
is Result.Success -> {
messageStore.updateMessageHistory(
it.value.entities.toMessageList(),
it.value.total,
)
}
is Result.Failure -> {
if (it.errorCode is ErrorCode.CancellationError) {
log.w { "Cancellation exception was thrown, while running getMessages() request." }
return
}
log.w { "History fetch failed with: $it" }
eventHandler.onEvent(Event.Error(ErrorCode.HistoryFetchFailure, it.message, it.errorCode.toCorrectiveAction()))
}
}
}
}
}

@Throws(IllegalStateException::class)
Expand Down Expand Up @@ -394,6 +407,9 @@ internal class MessagingClientImpl(
}
}
}
else -> {
log.w { "Messages of type: ${structuredMessage.type} are not supported." }
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,28 @@ internal class WebMessagingApi(
) {

/**
* @throws ResponseException if unsuccessful response from the service
* Returns Result.Success<MessageEntityList> upon successful response and parsing.
* Otherwise, return Result.Failure with description the failure.
*/
suspend fun getMessages(
jwt: String,
pageNumber: Int,
pageSize: Int = DEFAULT_PAGE_SIZE,
): MessageEntityList {
return client.get("${configuration.apiBaseUrl}/api/v2/webmessaging/messages") {
): Result<MessageEntityList> = try {
val response = client.get("${configuration.apiBaseUrl}/api/v2/webmessaging/messages") {
headerAuthorizationBearer(jwt)
parameter("pageNumber", pageNumber)
parameter("pageSize", pageSize)
}.body()
}
if (response.status.isSuccess()) {
Result.Success(response.body())
} else {
Result.Failure(ErrorCode.mapFrom(response.status.value), response.body())
}
} catch (cancellationException: CancellationException) {
Result.Failure(ErrorCode.CancellationError, cancellationException.message)
} catch (e: Exception) {
Result.Failure(ErrorCode.UnexpectedError, e.message)
}

@Throws(ResponseException::class, CancellationException::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ internal data class StructuredMessage(
Text,
@SerialName("Event")
Event,
@SerialName("Structured")
Structured,
}

@Serializable(with = ContentSerializer::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import com.genesys.cloud.messenger.transport.core.Attachment
import com.genesys.cloud.messenger.transport.core.Message
import com.genesys.cloud.messenger.transport.core.Message.Direction
import com.genesys.cloud.messenger.transport.core.events.toTransportEvent
import com.genesys.cloud.messenger.transport.shyrka.receive.MessageEntityList
import com.genesys.cloud.messenger.transport.shyrka.receive.StructuredMessage
import com.genesys.cloud.messenger.transport.shyrka.receive.isInbound
import com.soywiz.klock.DateTime

internal fun MessageEntityList.toMessageList(): List<Message> {
return this.entities.map {
internal fun List<StructuredMessage>.toMessageList(): List<Message> {
return this.filter { it.type != StructuredMessage.Type.Structured }.map {
it.toMessage()
}
}
Expand All @@ -23,7 +22,8 @@ internal fun StructuredMessage.toMessage(): Message {
type = type.name,
text = text,
timeStamp = channel?.time.fromIsoToEpochMilliseconds(),
attachments = content.filterIsInstance<StructuredMessage.Content.AttachmentContent>().toAttachments(),
attachments = content.filterIsInstance<StructuredMessage.Content.AttachmentContent>()
.toAttachments(),
events = events.mapNotNull { it.toTransportEvent() },
from = Message.Participant(
name = channel?.from?.nickname,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class WebMessagingApiTest {
@Test
fun whenFetchHistory() {
subject = buildWebMessagingApiWith { historyEngine() }
val expectedEntityList = TestWebMessagingApiResponses.testMessageEntityList
val expectedEntityList = Result.Success(TestWebMessagingApiResponses.testMessageEntityList)

val result = runBlocking {
withTimeout(DEFAULT_TIMEOUT) {
Expand All @@ -42,7 +42,7 @@ class WebMessagingApiTest {
fun whenFetchHistoryAndThereAreNoHistory() {
subject = buildWebMessagingApiWith { historyEngine() }

val expectedEntityList = TestWebMessagingApiResponses.emptyMessageEntityList
val expectedEntityList = Result.Success(TestWebMessagingApiResponses.emptyMessageEntityList)

val result = runBlocking {
withTimeout(DEFAULT_TIMEOUT) {
Expand Down
2 changes: 1 addition & 1 deletion transport/transport.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'transport'
spec.version = '2.4.0'
spec.version = '2.4.1'
spec.homepage = 'https://github.com/MyPureCloud/genesys-messenger-transport-mobile-sdk'
spec.source = { :http=> ''}
spec.authors = 'Genesys Cloud Services, Inc.'
Expand Down

0 comments on commit d684a64

Please sign in to comment.