diff --git a/build.gradle b/build.gradle index b624e918..5b2e085d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" - classpath "gradle.plugin.org.jmailen.gradle:kotlinter-gradle:${versions.kotlinter}" + classpath "org.jmailen.gradle:kotlinter-gradle:${versions.kotlinter}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" } } diff --git a/compat/build.gradle b/compat/build.gradle index f9fb3a02..edb01157 100644 --- a/compat/build.gradle +++ b/compat/build.gradle @@ -36,12 +36,6 @@ compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } -kotlin { - experimental { - coroutines "enable" - } -} - dokka { outputFormat = 'html' outputDirectory = "$buildDir/javadoc" diff --git a/compat/src/main/kotlin/chat/rocket/core/compat/Call.kt b/compat/src/main/kotlin/chat/rocket/core/compat/Call.kt index 91507bbb..b88a82d2 100644 --- a/compat/src/main/kotlin/chat/rocket/core/compat/Call.kt +++ b/compat/src/main/kotlin/chat/rocket/core/compat/Call.kt @@ -1,6 +1,6 @@ package chat.rocket.core.compat -import kotlinx.coroutines.experimental.Job +import kotlinx.coroutines.Job class Call(val job: Job) { fun cancel() { diff --git a/compat/src/main/kotlin/chat/rocket/core/compat/Server.kt b/compat/src/main/kotlin/chat/rocket/core/compat/Server.kt index 50c7ccdf..01586e4d 100644 --- a/compat/src/main/kotlin/chat/rocket/core/compat/Server.kt +++ b/compat/src/main/kotlin/chat/rocket/core/compat/Server.kt @@ -4,9 +4,10 @@ import chat.rocket.common.model.ServerInfo import chat.rocket.core.RocketChatClient import chat.rocket.core.compat.internal.callback import chat.rocket.core.internal.rest.serverInfo -import kotlinx.coroutines.experimental.CommonPool +import kotlinx.coroutines.Dispatchers -fun RocketChatClient.serverInfo(future: Callback): Call = - callback(CommonPool, future) { - serverInfo() - } \ No newline at end of file +/** + * Returns the current logged server information. + * Must be used with a coroutine context (async, launch, etc) + */ +fun RocketChatClient.serverInfo(future: Callback): Call = callback(Dispatchers.IO, future) { serverInfo() } \ No newline at end of file diff --git a/compat/src/main/kotlin/chat/rocket/core/compat/User.kt b/compat/src/main/kotlin/chat/rocket/core/compat/User.kt index 4b96a963..a1aa6322 100644 --- a/compat/src/main/kotlin/chat/rocket/core/compat/User.kt +++ b/compat/src/main/kotlin/chat/rocket/core/compat/User.kt @@ -4,17 +4,10 @@ import chat.rocket.core.RocketChatClient import chat.rocket.core.compat.internal.callback import chat.rocket.core.internal.rest.me import chat.rocket.core.model.Myself -import kotlinx.coroutines.experimental.CommonPool +import kotlinx.coroutines.Dispatchers /** * Returns the current logged user information, useful to check if the Token from TokenProvider * is still valid. Must be used with a coroutine context (async, launch, etc) - * - * @return Call - * @see - * @see RocketChatException */ -fun RocketChatClient.me(future: Callback): Call = - callback(CommonPool, future) { - me() - } \ No newline at end of file +fun RocketChatClient.me(future: Callback): Call = callback(Dispatchers.IO, future) { me() } \ No newline at end of file diff --git a/compat/src/main/kotlin/chat/rocket/core/compat/internal/Callback.kt b/compat/src/main/kotlin/chat/rocket/core/compat/internal/Callback.kt index 17ee9c7e..7dc43074 100644 --- a/compat/src/main/kotlin/chat/rocket/core/compat/internal/Callback.kt +++ b/compat/src/main/kotlin/chat/rocket/core/compat/internal/Callback.kt @@ -3,31 +3,35 @@ package chat.rocket.core.compat.internal import chat.rocket.common.RocketChatException import chat.rocket.core.compat.Call import chat.rocket.core.compat.Callback -import kotlinx.coroutines.experimental.AbstractCoroutine -import kotlinx.coroutines.experimental.CoroutineScope -import kotlinx.coroutines.experimental.DefaultDispatcher -import kotlinx.coroutines.experimental.Job -import kotlinx.coroutines.experimental.newCoroutineContext -import kotlin.coroutines.experimental.CoroutineContext -import kotlin.coroutines.experimental.startCoroutine +import kotlinx.coroutines.AbstractCoroutine +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.newCoroutineContext +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.startCoroutine @JvmOverloads fun callback( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, callback: Callback, block: suspend CoroutineScope.() -> T ): Call { - val newContext = newCoroutineContext(context) + val newContext = GlobalScope.newCoroutineContext(context) val job = Job(newContext[Job]) val coroutine = CallbackCoroutine(newContext + job, callback) block.startCoroutine(coroutine, coroutine) return Call(job) } +@UseExperimental(InternalCoroutinesApi::class) private class CallbackCoroutine( parentContext: CoroutineContext, private val callback: Callback ) : AbstractCoroutine(parentContext, true) { + override fun onCompleted(value: T) { callback.onSuccess(value) } diff --git a/core/build.gradle b/core/build.gradle index 53bd1542..957c14b0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -41,12 +41,6 @@ compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } -kotlin { - experimental { - coroutines "enable" - } -} - dokka { outputFormat = 'html' outputDirectory = "$buildDir/javadoc" diff --git a/core/src/main/kotlin/chat/rocket/core/RocketChatClient.kt b/core/src/main/kotlin/chat/rocket/core/RocketChatClient.kt index e282c3a7..90666980 100644 --- a/core/src/main/kotlin/chat/rocket/core/RocketChatClient.kt +++ b/core/src/main/kotlin/chat/rocket/core/RocketChatClient.kt @@ -27,11 +27,14 @@ import chat.rocket.core.model.Myself import chat.rocket.core.model.Room import chat.rocket.core.model.url.MetaJsonAdapter import com.squareup.moshi.Moshi -import kotlinx.coroutines.experimental.channels.Channel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel import okhttp3.HttpUrl import okhttp3.MediaType import okhttp3.OkHttpClient import java.security.InvalidParameterException +import kotlin.coroutines.CoroutineContext class RocketChatClient private constructor( internal val httpClient: OkHttpClient, @@ -39,7 +42,10 @@ class RocketChatClient private constructor( userAgent: String, internal val tokenRepository: TokenRepository, internal val logger: Logger -) { +) : CoroutineScope { + override val coroutineContext: CoroutineContext + get() = Dispatchers.Default + internal val moshi: Moshi = Moshi.Builder() .add(FallbackSealedClassJsonAdapter.ADAPTER_FACTORY) .add(RestResult.JsonAdapterFactory()) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/AttachmentAdapter.kt b/core/src/main/kotlin/chat/rocket/core/internal/AttachmentAdapter.kt index 5d248a1a..96d8daf7 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/AttachmentAdapter.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/AttachmentAdapter.kt @@ -24,34 +24,34 @@ class AttachmentAdapter(moshi: Moshi, private val logger: Logger) : JsonAdapter< private val actionAdapter = moshi.adapter(ButtonAction::class.java) private val NAMES = arrayOf( - "title", // 0 - "type", // 1 - "description", // 2 - "author_name", // 3 - "text", // 4 - "thumb_url", // 5 - "color", // 6 - "title_link", // 7 - "title_link_download", // 8 - "image_url", // 9 - "image_type", // 10 - "image_size", // 11 - "video_url", // 12 - "video_type", // 13 - "video_size", // 14 - "audio_url", // 15 - "audio_type", // 16 - "audio_size", // 17 - "message_link", // 18 - "attachments", // 19 - "ts", // 20 - "author_icon", // 21 - "author_link", // 22 - "image_preview", // 23 - "fields", // 24 - "fallback", // 25 - "button_alignment", // 26 - "actions" // 27 + "title", // 0 + "type", // 1 + "description", // 2 + "author_name", // 3 + "text", // 4 + "thumb_url", // 5 + "color", // 6 + "title_link", // 7 + "title_link_download", // 8 + "image_url", // 9 + "image_type", // 10 + "image_size", // 11 + "video_url", // 12 + "video_type", // 13 + "video_size", // 14 + "audio_url", // 15 + "audio_type", // 16 + "audio_size", // 17 + "message_link", // 18 + "attachments", // 19 + "ts", // 20 + "author_icon", // 21 + "author_link", // 22 + "image_preview", // 23 + "fields", // 24 + "fallback", // 25 + "button_alignment", // 26 + "actions" // 27 ) private val OPTIONS = JsonReader.Options.of(*NAMES) @@ -61,34 +61,34 @@ class AttachmentAdapter(moshi: Moshi, private val logger: Logger) : JsonAdapter< return reader.nextNull() } - var title: String? = null // 0 - var type: String? = null // 1 - var description: String? = null // 2 - var authorName: String? = null // 3 - var text: String? = null // 4 - var thumbUrl: String? = null // 5 - var color: Color? = null // 6 - var titleLink: String? = null // 7 - var titleLinkDownload = false // 8 - var imageUrl: String? = null // 9 - var imageType: String? = null // 10 - var imageSize: Long? = null // 11 - var videoUrl: String? = null // 12 - var videoType: String? = null // 13 - var videoSize: Long? = null // 14 - var audioUrl: String? = null // 15 - var audioType: String? = null // 16 - var audioSize: Long? = null // 17 - var messageLink: String? = null // 18 + var title: String? = null // 0 + var type: String? = null // 1 + var description: String? = null // 2 + var authorName: String? = null // 3 + var text: String? = null // 4 + var thumbUrl: String? = null // 5 + var color: Color? = null // 6 + var titleLink: String? = null // 7 + var titleLinkDownload = false // 8 + var imageUrl: String? = null // 9 + var imageType: String? = null // 10 + var imageSize: Long? = null // 11 + var videoUrl: String? = null // 12 + var videoType: String? = null // 13 + var videoSize: Long? = null // 14 + var audioUrl: String? = null // 15 + var audioType: String? = null // 16 + var audioSize: Long? = null // 17 + var messageLink: String? = null // 18 var attachments: List? = null // 19 - var timestamp: Long? = null // 20 - var authorIcon: String? = null // 21 - var authorLink: String? = null // 22 - var imagePreview: String? = null // 23 - var fields: List? = null // 24 - var fallback: String? = null // 25 - var buttonAlignment: String? = null // 26 - var actions: List? = null // 27 + var timestamp: Long? = null // 20 + var authorIcon: String? = null // 21 + var authorLink: String? = null // 22 + var imagePreview: String? = null // 23 + var fields: List? = null // 24 + var fallback: String? = null // 25 + var buttonAlignment: String? = null // 26 + var actions: List? = null // 27 reader.beginObject() while (reader.hasNext()) { diff --git a/core/src/main/kotlin/chat/rocket/core/internal/RoomListAdapter.kt b/core/src/main/kotlin/chat/rocket/core/internal/RoomListAdapter.kt index 66aaea6e..4a3b5689 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/RoomListAdapter.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/RoomListAdapter.kt @@ -24,7 +24,7 @@ internal class RoomListAdapter(moshi: Moshi, private val logger: Logger) : JsonA private val adapter = moshi.adapter(Room::class.java) override fun toJson(writer: JsonWriter, value: List?) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun fromJson(reader: JsonReader): List? { diff --git a/core/src/main/kotlin/chat/rocket/core/internal/model/CreateNewChannelPayload.kt b/core/src/main/kotlin/chat/rocket/core/internal/model/CreateNewChannelPayload.kt index 708ff2ce..128796cb 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/model/CreateNewChannelPayload.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/model/CreateNewChannelPayload.kt @@ -4,7 +4,7 @@ import com.squareup.moshi.Json import se.ansman.kotshi.JsonSerializable @JsonSerializable -data class CreateNewChannelPayload ( +data class CreateNewChannelPayload( @Json(name = "name") val channelName: String, @Json(name = "members") val membersToInvite: List?, val readOnly: Boolean? diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/ChatRoom.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/ChatRoom.kt index ba65185e..515db66f 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/ChatRoom.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/ChatRoom.kt @@ -7,11 +7,11 @@ import chat.rocket.core.internal.realtime.message.roomsStreamMessage import chat.rocket.core.internal.realtime.message.streamRoomMessages import chat.rocket.core.internal.realtime.message.streamTypingMessage import chat.rocket.core.internal.realtime.message.typingMessage -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext suspend fun RocketChatClient.setTypingStatus(roomId: String, username: String, isTyping: Boolean) = - withContext(CommonPool) { + withContext(Dispatchers.IO) { socket.send(typingMessage(socket.generateId(), roomId, username, isTyping)) } @@ -52,4 +52,4 @@ fun RocketChatClient.createDirectMessage(username: String, callback: (Boolean, S subscriptionsMap[id] = callback return id } -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/message/MethodCall.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/message/MethodCall.kt index a0c541fc..9d5220f3 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/message/MethodCall.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/message/MethodCall.kt @@ -28,4 +28,4 @@ internal fun typingMessage(id: String, roomId: String, username: String, isTypin internal fun createDirectMessage(id: String, username: String): String { return newMessage("createDirectMessage", id, "\"$username\"") -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/Socket.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/Socket.kt index 9dd5be32..f7da3672 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/Socket.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/Socket.kt @@ -15,24 +15,25 @@ import chat.rocket.core.model.Message import chat.rocket.core.model.Myself import chat.rocket.core.model.Room import com.squareup.moshi.JsonAdapter -import kotlinx.coroutines.experimental.Job -import kotlinx.coroutines.experimental.channels.Channel -import kotlinx.coroutines.experimental.channels.SendChannel -import kotlinx.coroutines.experimental.delay -import kotlinx.coroutines.experimental.isActive -import kotlinx.coroutines.experimental.launch -import kotlinx.coroutines.experimental.newSingleThreadContext -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.SendChannel +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.newSingleThreadContext +import kotlinx.coroutines.withContext import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener import okio.ByteString -import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger -import kotlin.coroutines.experimental.coroutineContext +import kotlin.coroutines.CoroutineContext -const val PING_INTERVAL = 15L +const val PING_INTERVAL = 15000L class Socket( internal val client: RocketChatClient, @@ -42,7 +43,10 @@ class Socket( internal val userDataChannel: SendChannel, internal val activeUsersChannel: SendChannel, internal val typingStatusChannel: SendChannel> -) : WebSocketListener() { +) : WebSocketListener(), CoroutineScope { + internal var parentJob = Job() + override val coroutineContext: CoroutineContext + get() = Dispatchers.Default + parentJob private val request: Request = Request.Builder() .url("${client.url}/websocket") @@ -60,7 +64,6 @@ class Socket( internal var socket: WebSocket? = null private var processingChannel: Channel? = null internal val statusChannelList = ArrayList>() - internal var parentJob: Job? = null private var readJob: Job? = null private var pingJob: Job? = null private var timeoutJob: Job? = null @@ -85,7 +88,7 @@ class Socket( selfDisconnect = false // reset id counter currentId.set(1) - parentJob?.cancel() + parentJob.cancel() reconnectJob?.cancel() if (resetCounter) { @@ -116,30 +119,26 @@ class Socket( private fun startReconnection() { // Ignore self disconnection if (selfDisconnect) { - logger.info { "Self disconnected, won't try to reconnect." } + logger.info { "SELF DISCONNECTED, WON'T TRY TO RECONNECT." } return } - logger.info { "startReconnection" } + logger.info { "START RECONNECTION" } if (reconnectionStrategy.shouldRetry) { reconnectJob?.cancel() reconnectJob = launch(connectionContext) { - logger.debug { - "Reconnecting in: ${reconnectionStrategy.reconnectInterval}" - } + logger.debug { "RECONNECTING IN: ${reconnectionStrategy.reconnectInterval}" } delayReconnection(reconnectionStrategy.reconnectInterval) if (!isActive) { - logger.debug { - "Reconnect job inactive, ignoring" - } + logger.debug { "RECONNECT JOB INACTIVE, IGNORING" } return@launch } reconnectionStrategy.processAttempts() connect(false) } } else { - logger.info { "Exhausted reconnection attempts: ${reconnectionStrategy.numberOfAttempts} - ${reconnectionStrategy.maxAttempts}" } + logger.info { "EXHAUSTED RECONNECTION ATTEMPTS: ${reconnectionStrategy.numberOfAttempts} - ${reconnectionStrategy.maxAttempts}" } } } @@ -148,9 +147,7 @@ class Socket( withContext(connectionContext) { for (second in 0..(seconds - 1)) { if (!coroutineContext.isActive) { - logger.debug { - "Reconnect job inactive, ignoring" - } + logger.debug { "Reconnect job inactive, ignoring" } return@withContext } val left = seconds - second @@ -165,7 +162,7 @@ class Socket( messagesProcessed++ logger.debug { val len = Math.min(40, text.length) - "Process Incoming message: ${text.substring(0, len)}" + "PROCESS INCOMING MESSAGE: ${text.substring(0, len)}" } // Ignore empty or invalid messages @@ -214,17 +211,13 @@ class Socket( // FIXME - for now just set the state to connected setState(State.Connected()) - //Also process the message + // Also process the message if (message.type == MessageType.ADDED) { processSubscriptionsAdded(message, text) } } - MessageType.RESULT -> { - processLoginResult(text) - } - MessageType.PING -> { - send(pongMessage()) - } + MessageType.RESULT -> processLoginResult(text) + MessageType.PING -> send(pongMessage()) else -> { // IGNORING FOR NOW. } @@ -234,74 +227,53 @@ class Socket( private fun processMessage(message: SocketMessage, text: String) { when (message.type) { MessageType.PING -> { - logger.debug { "sending pong - messages received $messagesReceived - messages processed $messagesProcessed" } + logger.debug { "Sending pong - messages received $messagesReceived - messages processed $messagesProcessed" } send(pongMessage()) } - MessageType.ADDED -> { - processSubscriptionsAdded(message, text) - } - MessageType.REMOVED -> { - processSubscriptionsRemoved(message, text) - } - MessageType.CHANGED -> { - processSubscriptionsChanged(message, text) - } - MessageType.READY -> { - processSubscriptionResult(text) - } - MessageType.RESULT -> { - processMethodResult(text) - } - MessageType.ERROR -> { - logger.info { "Error: ${message.errorReason}" } - } - else -> { - logger.debug { "Ignoring message type: ${message.type}" } - } + MessageType.ADDED -> processSubscriptionsAdded(message, text) + MessageType.REMOVED -> processSubscriptionsRemoved(message, text) + MessageType.CHANGED -> processSubscriptionsChanged(message, text) + MessageType.READY -> processSubscriptionResult(text) + MessageType.RESULT -> processMethodResult(text) + MessageType.ERROR -> logger.warn { "ERROR on processMessage: ${message.errorReason}" } + else -> logger.debug { "Ignoring message type: ${message.type}" } } } internal fun send(message: String) { - logger.debug { - "Sending message: $message" - } + logger.debug { "Sending messagE: $message" } socket?.send(message) } private fun reschedulePing(type: MessageType) { - logger.debug { - "Rescheduling ping in $PING_INTERVAL seconds" - } + logger.debug { "Rescheduling ping in $PING_INTERVAL milliseconds" } timeoutJob?.cancel() - pingJob?.cancel() - pingJob = launch(parent = parentJob) { + + pingJob = launch { logger.debug { "Scheduling ping" } - delay(PING_INTERVAL, TimeUnit.SECONDS) + delay(PING_INTERVAL) - logger.debug { "running ping if active" } + logger.debug { "Running ping if active" } if (!isActive) return@launch schedulePingTimeout() - logger.debug { "sending ping - messages received $messagesReceived - messages processed $messagesProcessed" } + logger.debug { "Sending ping - messages received $messagesReceived - messages processed $messagesProcessed" } send(pingMessage()) } } private suspend fun schedulePingTimeout() { val timeout = (PING_INTERVAL * 1.5).toLong() - logger.debug { "Scheduling ping timeout in $timeout" } - timeoutJob = launch(parent = parentJob) { - delay(timeout, TimeUnit.SECONDS) - + logger.debug { "Scheduling ping timeout in $timeout milliseconds" } + timeoutJob = launch(parentJob) { + delay(timeout) if (!isActive) return@launch when (currentState) { is State.Disconnected, - is State.Disconnecting -> { - logger.warn { "PONG not received, but already disconnected" } - } + is State.Disconnecting -> logger.warn { "Pong not received, but already disconnected" } else -> { - logger.warn { "PONG not received" } + logger.warn { "Pong not received" } socket?.cancel() } } @@ -331,11 +303,11 @@ class Socket( private fun close() { processingChannel?.close() - parentJob?.cancel() + parentJob.cancel() } override fun onOpen(webSocket: WebSocket, response: Response?) { - readJob = launch(parent = parentJob) { + readJob = launch { for (message in processingChannel!!) { processIncomingMessage(message) } @@ -345,7 +317,7 @@ class Socket( } override fun onFailure(webSocket: WebSocket, throwable: Throwable?, response: Response?) { - logger.warn { throwable?.message } + logger.warn { "Socket.onFailure(). THROWABLE MESSAGE: ${throwable?.message} - RESPONSE MESSAGE: ${response?.message()}" } throwable?.printStackTrace() setState(State.Disconnected()) close() @@ -353,19 +325,25 @@ class Socket( } override fun onClosing(webSocket: WebSocket, code: Int, reason: String?) { - logger.debug { "webSocket.onClosing - CLOSING SOCKET" } + logger.warn { "Socket.onClosing() called. Received CODE = $code - Received REASON = $reason" } setState(State.Disconnecting()) startReconnection() } + override fun onClosed(webSocket: WebSocket, code: Int, reason: String?) { + logger.warn { "Socket.onClosed() called. Received CODE = $code - Received REASON = $reason" } + setState(State.Disconnected()) + close() + startReconnection() + } override fun onMessage(webSocket: WebSocket, text: String?) { - logger.debug { "Received text message: $text, channel: $processingChannel" } + logger.warn { "Socket.onMessage(). Received TEXT = $text for processing channel = $processingChannel" } text?.let { messagesReceived++ - if (parentJob == null || !parentJob!!.isActive) { + if (!parentJob.isActive) { logger.debug { "Parent job: $parentJob" } } - launch(parent = parentJob) { + launch { if (processingChannel == null || processingChannel?.isFull == true || processingChannel?.isClosedForSend == true) { logger.debug { "processing channel is in trouble... $processingChannel - full ${processingChannel?.isFull} - closedForSend ${processingChannel?.isClosedForSend}" } } @@ -375,20 +353,10 @@ class Socket( } override fun onMessage(webSocket: WebSocket, bytes: ByteString?) { - logger.debug { "Received ByteString message: $bytes" } - } - - override fun onClosed(webSocket: WebSocket, code: Int, reason: String?) { - setState(State.Disconnected()) - close() - startReconnection() + logger.warn { "Socket.onMessage() called. Received ByteString message: $bytes" } } } -fun RocketChatClient.connect(resetCounter: Boolean = false) { - socket.connect(resetCounter) -} +fun RocketChatClient.connect(resetCounter: Boolean = false) = socket.connect(resetCounter) -fun RocketChatClient.disconnect() { - socket.disconnect() -} +fun RocketChatClient.disconnect() = socket.disconnect() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyRoom.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyRoom.kt index 889f2fbb..b85b721a 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyRoom.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyRoom.kt @@ -1,7 +1,7 @@ package chat.rocket.core.internal.realtime.socket.message.collection import chat.rocket.core.internal.realtime.socket.Socket -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.launch import org.json.JSONObject internal const val STREAM_NOTIFY_ROOM = "stream-notify-room" @@ -12,9 +12,7 @@ internal fun Socket.processNotifyRoomStream(text: String) { val fields = json.getJSONObject("fields") val array = fields.getJSONArray("args") - launch(parent = parentJob) { - typingStatusChannel.send(Pair(array.getString(0), array.getBoolean(1))) - } + launch(parentJob) { typingStatusChannel.send(Pair(array.getString(0), array.getBoolean(1))) } } catch (ex: Exception) { ex.printStackTrace() } diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyUser.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyUser.kt index bfccabf4..ca083a53 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyUser.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamNotifyUser.kt @@ -5,7 +5,7 @@ import chat.rocket.core.internal.realtime.socket.Socket import chat.rocket.core.internal.realtime.socket.model.StreamMessage import chat.rocket.core.internal.realtime.socket.model.Type import chat.rocket.core.model.Room -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.launch import org.json.JSONObject import java.security.InvalidParameterException @@ -43,7 +43,7 @@ private fun Socket.processRoomStream(state: String, data: JSONObject) { if (parentJob == null || !parentJob!!.isActive) { logger.debug { "Parent job: $parentJob" } } - launch(parent = parentJob) { + launch(parentJob) { if (roomsChannel.isFull || roomsChannel.isClosedForSend) { logger.debug { "Rooms channel is in trouble... $roomsChannel - full ${roomsChannel.isFull} - closedForSend ${roomsChannel.isClosedForSend}" } } @@ -66,9 +66,7 @@ private fun Socket.processSubscriptionStream(state: String, data: JSONObject) { } subscription?.apply { - launch(parent = parentJob) { - subscriptionsChannel.send(StreamMessage(getMessageType(state), subscription)) - } + launch(parentJob) { subscriptionsChannel.send(StreamMessage(getMessageType(state), subscription)) } } } diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamRoomMessages.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamRoomMessages.kt index 67b39620..4f45363e 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamRoomMessages.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/StreamRoomMessages.kt @@ -2,7 +2,7 @@ package chat.rocket.core.internal.realtime.socket.message.collection import chat.rocket.core.internal.realtime.socket.Socket import chat.rocket.core.model.Message -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.launch import org.json.JSONObject internal const val STREAM_ROOM_MESSAGES = "stream-room-messages" @@ -17,9 +17,7 @@ internal fun Socket.processRoomMessage(text: String) { val message = adapter.fromJson(data.toString()) message?.let { - launch(parent = parentJob) { - messagesChannel.send(message) - } + launch(parentJob) { messagesChannel.send(message) } } } catch (ex: Exception) { ex.printStackTrace() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/Users.kt b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/Users.kt index 65086d9b..40049932 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/Users.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/realtime/socket/message/collection/Users.kt @@ -3,7 +3,7 @@ package chat.rocket.core.internal.realtime.socket.message.collection import chat.rocket.common.model.User import chat.rocket.core.internal.realtime.socket.Socket import chat.rocket.core.model.Myself -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.launch import org.json.JSONObject internal const val USERS = "users" @@ -35,7 +35,7 @@ private fun Socket.processUserDataStream(json: JSONObject, id: String) { if (parentJob == null || !parentJob!!.isActive) { logger.debug { "Parent job: $parentJob" } } - launch(parent = parentJob) { + launch(parentJob) { if (userDataChannel.isFull || userDataChannel.isClosedForSend) { logger.debug { "User Data channel is in trouble... $userDataChannel - full ${userDataChannel.isFull} - closedForSend ${userDataChannel.isClosedForSend}" } } @@ -64,8 +64,6 @@ private fun Socket.processActiveUsersStream(json: JSONObject, id: String) { if (activeUsersChannel.isFull || activeUsersChannel.isClosedForSend) { logger.debug { "Active Users channel is in trouble... $activeUsersChannel - full ${activeUsersChannel.isFull} - closedForSend ${activeUsersChannel.isClosedForSend}" } } - launch(parent = parentJob) { - activeUsersChannel.send(user) - } + launch(parentJob) { activeUsersChannel.send(user) } } } \ No newline at end of file diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Channel.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Channel.kt index 5fb11dc2..32682272 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Channel.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Channel.kt @@ -8,8 +8,8 @@ import chat.rocket.core.internal.model.CreateNewChannelPayload import chat.rocket.core.model.DirectMessage import chat.rocket.core.model.Room import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.RequestBody /** @@ -25,7 +25,7 @@ suspend fun RocketChatClient.createChannel( name: String, usersList: List?, readOnly: Boolean? = false -): Room = withContext(CommonPool) { +): Room = withContext(Dispatchers.IO) { val payload = CreateNewChannelPayload(name, usersList, readOnly) val adapter = moshi.adapter(CreateNewChannelPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -46,7 +46,7 @@ suspend fun RocketChatClient.createChannel( * @return A DirectMessage object. */ suspend fun RocketChatClient.createDirectMessage(username: String): DirectMessage = - withContext(CommonPool) { + withContext(Dispatchers.IO) { val payload = CreateDirectMessagePayload(username = username) val adapter = moshi.adapter(CreateDirectMessagePayload::class.java) val payloadBody = adapter.toJson(payload) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/ChatRoom.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/ChatRoom.kt index c7ba2a78..8cb56e1f 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/ChatRoom.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/ChatRoom.kt @@ -22,8 +22,8 @@ import chat.rocket.core.model.Room import chat.rocket.core.model.PagedResult import chat.rocket.core.model.attachment.GenericAttachment import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.RequestBody /** @@ -40,7 +40,7 @@ suspend fun RocketChatClient.getMembers( roomType: RoomType, offset: Long, count: Long -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, getRestApiMethodNameByRoomType(roomType, "members")) .addQueryParameter("roomId", roomId) .addQueryParameter("offset", offset.toString()) @@ -70,7 +70,7 @@ suspend fun RocketChatClient.getMentions( roomId: String, offset: Long, count: Long -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "channels.getAllUserMentionsByChannel") .addQueryParameter("roomId", roomId) .addQueryParameter("offset", offset.toString()) @@ -101,8 +101,8 @@ suspend fun RocketChatClient.getFavoriteMessages( roomId: String, roomType: RoomType, offset: Int -): PagedResult> = withContext(CommonPool) { - val userId = tokenRepository.get(this.url)?.userId +): PagedResult> = withContext(Dispatchers.IO) { + val userId = tokenRepository.get(url)?.userId val httpUrl = requestUrl(restUrl, getRestApiMethodNameByRoomType(roomType, "messages")) .addQueryParameter("roomId", roomId) @@ -133,7 +133,7 @@ suspend fun RocketChatClient.getPinnedMessages( roomId: String, roomType: RoomType, offset: Int? = 0 -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl( restUrl, getRestApiMethodNameByRoomType(roomType, "messages") @@ -167,7 +167,7 @@ suspend fun RocketChatClient.getFiles( roomId: String, roomType: RoomType, offset: Int? = 0 -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl( restUrl, getRestApiMethodNameByRoomType(roomType, "files") @@ -201,7 +201,7 @@ suspend fun RocketChatClient.getInfo( roomId: String, roomName: String?, roomType: RoomType -): Room = withContext(CommonPool) { +): Room = withContext(Dispatchers.IO) { val url = requestUrl(restUrl, getRestApiMethodNameByRoomType(roomType, "info")) .addQueryParameter("roomId", roomId) .addQueryParameter("roomName", roomName) @@ -219,7 +219,7 @@ suspend fun RocketChatClient.getInfo( * @param roomId The ID of the room. */ suspend fun RocketChatClient.markAsRead(roomId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val payload = ChatRoomPayload(roomId) val adapter = moshi.adapter(ChatRoomPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -239,7 +239,7 @@ suspend fun RocketChatClient.markAsRead(roomId: String) { * @param roomId The ID of the room. */ suspend fun RocketChatClient.markAsUnread(roomId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val payload = ChatRoomUnreadPayload(roomId) val adapter = moshi.adapter(ChatRoomUnreadPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -254,7 +254,7 @@ suspend fun RocketChatClient.markAsUnread(roomId: String) { } // TODO: Add doc. -suspend fun RocketChatClient.joinChat(roomId: String): Boolean = withContext(CommonPool) { +suspend fun RocketChatClient.joinChat(roomId: String): Boolean = withContext(Dispatchers.IO) { val payload = RoomIdPayload(roomId) val adapter = moshi.adapter(RoomIdPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -278,7 +278,7 @@ suspend fun RocketChatClient.joinChat(roomId: String): Boolean = withContext(Com suspend fun RocketChatClient.leaveChat( roomId: String, roomType: RoomType -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = RoomIdPayload(roomId) val adapter = moshi.adapter(RoomIdPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -304,7 +304,7 @@ suspend fun RocketChatClient.rename( roomId: String, roomType: RoomType, newName: String -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = ChatRoomNamePayload(roomId, newName) val adapter = moshi.adapter(ChatRoomNamePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -330,7 +330,7 @@ suspend fun RocketChatClient.setReadOnly( roomId: String, roomType: RoomType, readOnly: Boolean -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = ChatRoomReadOnlyPayload(roomId, readOnly) val adapter = moshi.adapter(ChatRoomReadOnlyPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -356,7 +356,7 @@ suspend fun RocketChatClient.setType( roomId: String, roomType: RoomType, type: String -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = ChatRoomTypePayload(roomId, type) val adapter = moshi.adapter(ChatRoomTypePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -382,7 +382,7 @@ suspend fun RocketChatClient.setJoinCode( roomId: String, roomType: RoomType, joinCode: String -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = ChatRoomJoinCodePayload(roomId, joinCode) val adapter = moshi.adapter(ChatRoomJoinCodePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -408,7 +408,7 @@ suspend fun RocketChatClient.setTopic( roomId: String, roomType: RoomType, topic: String? -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = ChatRoomTopicPayload(roomId, topic) val adapter = moshi.adapter(ChatRoomTopicPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -434,7 +434,7 @@ suspend fun RocketChatClient.setDescription( roomId: String, roomType: RoomType, description: String? -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = ChatRoomDescriptionPayload(roomId, description) val adapter = moshi.adapter(ChatRoomDescriptionPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -460,7 +460,7 @@ suspend fun RocketChatClient.setAnnouncement( roomId: String, roomType: RoomType, announcement: String? -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = ChatRoomAnnouncementPayload(roomId, announcement) val adapter = moshi.adapter(ChatRoomAnnouncementPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -486,7 +486,7 @@ suspend fun RocketChatClient.archive( roomId: String, roomType: RoomType, archiveRoom: Boolean -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = RoomIdPayload(roomId) val adapter = moshi.adapter(RoomIdPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -513,7 +513,7 @@ suspend fun RocketChatClient.hide( roomId: String, roomType: RoomType, hideRoom: Boolean = true -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = RoomIdPayload(roomId) val adapter = moshi.adapter(RoomIdPayload::class.java) val payloadBody = adapter.toJson(payload) @@ -551,7 +551,7 @@ suspend fun RocketChatClient.show( suspend fun RocketChatClient.favorite( roomId: String, favorite: Boolean -) = withContext(CommonPool) { +) = withContext(Dispatchers.IO) { val payload = ChatRoomFavoritePayload(roomId, favorite) val adapter = moshi.adapter(ChatRoomFavoritePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -573,7 +573,7 @@ suspend fun RocketChatClient.favorite( suspend fun RocketChatClient.searchMessages( roomId: String, searchText: String -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "chat.search") .addQueryParameter("roomId", roomId) .addQueryParameter("searchText", searchText) @@ -601,7 +601,7 @@ suspend fun RocketChatClient.searchMessages( suspend fun RocketChatClient.chatRoomRoles( roomType: RoomType, roomName: String -): List = withContext(CommonPool) { +): List = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, getRestApiMethodNameByRoomType(roomType, "roles")) .addQueryParameter("roomName", roomName) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Commands.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Commands.kt index 8e3c5cbd..d8e0c4e7 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Commands.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Commands.kt @@ -7,11 +7,11 @@ import chat.rocket.core.internal.model.CommandPayload import chat.rocket.core.model.Command import chat.rocket.core.model.PagedResult import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.RequestBody -suspend fun RocketChatClient.commands(offset: Int = 0, count: Int = 0): PagedResult> = withContext(CommonPool) { +suspend fun RocketChatClient.commands(offset: Int = 0, count: Int = 0): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "commands.list") .addQueryParameter("offset", offset.toString()) .addQueryParameter("count", count.toString()) @@ -24,7 +24,7 @@ suspend fun RocketChatClient.commands(offset: Int = 0, count: Int = 0): PagedRes return@withContext PagedResult>(result.result(), (result.total()) ?: 0, result.offset() ?: 0) } -suspend fun RocketChatClient.runCommand(command: Command, roomId: String): Boolean = withContext(CommonPool) { +suspend fun RocketChatClient.runCommand(command: Command, roomId: String): Boolean = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "commands.run") .build() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/CustomEmoji.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/CustomEmoji.kt index 94d7fc60..6206241f 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/CustomEmoji.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/CustomEmoji.kt @@ -4,10 +4,10 @@ import chat.rocket.core.RocketChatClient import chat.rocket.core.internal.RestResult import chat.rocket.core.model.CustomEmoji import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext -suspend fun RocketChatClient.getCustomEmojis(): List = withContext(CommonPool) { +suspend fun RocketChatClient.getCustomEmojis(): List = withContext(Dispatchers.IO) { val url = requestUrl(restUrl, "emoji-custom").build() val request = requestBuilderForAuthenticatedMethods(url).get().build() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Login.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Login.kt index 5be58564..b21f1736 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Login.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Login.kt @@ -17,8 +17,8 @@ import chat.rocket.core.internal.model.ForgotPasswordPayload import chat.rocket.core.internal.model.CasData import chat.rocket.core.internal.model.OauthData import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.RequestBody /** @@ -33,23 +33,24 @@ import okhttp3.RequestBody * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.login(username: String, password: String, pin: String? = null): Token = withContext(CommonPool) { - val payload = UsernameLoginPayload(username, password, pin) - val adapter = moshi.adapter(UsernameLoginPayload::class.java) +suspend fun RocketChatClient.login(username: String, password: String, pin: String? = null): Token = + withContext(Dispatchers.IO) { + val payload = UsernameLoginPayload(username, password, pin) + val adapter = moshi.adapter(UsernameLoginPayload::class.java) - val payloadBody = adapter.toJson(payload) - val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) + val payloadBody = adapter.toJson(payload) + val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() - val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) - val result = handleRestCall>(request, type).result() + val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) + val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) - result -} + result + } /** * Login with email and password. @@ -63,20 +64,20 @@ suspend fun RocketChatClient.login(username: String, password: String, pin: Stri * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.loginWithEmail(email: String, password: String, pin: String? = null): Token = withContext(CommonPool) { +suspend fun RocketChatClient.loginWithEmail(email: String, password: String, pin: String? = null): Token = withContext(Dispatchers.IO) { val payload = EmailLoginPayload(email, password, pin) val adapter = moshi.adapter(EmailLoginPayload::class.java) val payloadBody = adapter.toJson(payload) val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) result } @@ -93,20 +94,20 @@ suspend fun RocketChatClient.loginWithEmail(email: String, password: String, pin * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.loginWithLdap(username: String, password: String): Token = withContext(CommonPool) { +suspend fun RocketChatClient.loginWithLdap(username: String, password: String): Token = withContext(Dispatchers.IO) { val payload = LdapLoginPayload(true, username, password) val adapter = moshi.adapter(LdapLoginPayload::class.java) val payloadBody = adapter.toJson(payload) val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) result } @@ -122,20 +123,20 @@ suspend fun RocketChatClient.loginWithLdap(username: String, password: String): * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.loginWithCas(casCredential: String): Token = withContext(CommonPool) { +suspend fun RocketChatClient.loginWithCas(casCredential: String): Token = withContext(Dispatchers.IO) { val payload = CasLoginPayload(CasData(casCredential)) val adapter = moshi.adapter(CasLoginPayload::class.java) val payloadBody = adapter.toJson(payload) val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) result } @@ -151,20 +152,20 @@ suspend fun RocketChatClient.loginWithCas(casCredential: String): Token = withCo * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.loginWithSaml(samlCredential: String): Token = withContext(CommonPool) { +suspend fun RocketChatClient.loginWithSaml(samlCredential: String): Token = withContext(Dispatchers.IO) { val payload = SamlLoginPayload(true, samlCredential) val adapter = moshi.adapter(SamlLoginPayload::class.java) val payloadBody = adapter.toJson(payload) val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) result } @@ -181,20 +182,20 @@ suspend fun RocketChatClient.loginWithSaml(samlCredential: String): Token = with * @see [Token] * @see [chat.rocket.core.TokenRepository] */ -suspend fun RocketChatClient.loginWithOauth(credentialToken: String, credentialSecret: String): Token = withContext(CommonPool) { +suspend fun RocketChatClient.loginWithOauth(credentialToken: String, credentialSecret: String): Token = withContext(Dispatchers.IO) { val payload = OauthLoginPayload(OauthData(credentialToken, credentialSecret)) val adapter = moshi.adapter(OauthLoginPayload::class.java) val payloadBody = adapter.toJson(payload) val body = RequestBody.create(MEDIA_TYPE_JSON, payloadBody) - val url = requestUrl(restUrl, "login").build() - val request = requestBuilder(url).post(body).build() + val httpUrl = requestUrl(restUrl, "login").build() + val request = requestBuilder(httpUrl).post(body).build() val type = Types.newParameterizedType(RestResult::class.java, Token::class.java) val result = handleRestCall>(request, type).result() - tokenRepository.save(this.url, result) + tokenRepository.save(url, result) result } @@ -218,7 +219,7 @@ suspend fun RocketChatClient.signup( name: String, username: String, password: String -): User = withContext(CommonPool) { +): User = withContext(Dispatchers.IO) { val payload = SignUpPayload(username, email, password, name) val adapter = moshi.adapter(SignUpPayload::class.java) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Logout.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Logout.kt index 6dc2fa2e..b27e36b0 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Logout.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Logout.kt @@ -1,14 +1,14 @@ package chat.rocket.core.internal.rest import chat.rocket.core.RocketChatClient -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext /** * Logout user from the current logged-in server. */ suspend fun RocketChatClient.logout() { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "logout").build() val request = requestBuilderForAuthenticatedMethods(httpUrl).get().build() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Message.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Message.kt index 6a0586ae..5958c171 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Message.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Message.kt @@ -16,8 +16,8 @@ import chat.rocket.core.model.PagedResult import chat.rocket.core.model.ReadReceipt import chat.rocket.core.model.attachment.Attachment import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.FormBody import okhttp3.MediaType import okhttp3.MultipartBody @@ -45,7 +45,7 @@ suspend fun RocketChatClient.sendMessage( emoji: String? = null, avatar: String? = null, attachments: List? = null -): Message = withContext(CommonPool) { +): Message = withContext(Dispatchers.IO) { val payload = SendMessagePayload( SendMessageBody(messageId, roomId, message, alias, emoji, avatar, attachments) ) @@ -79,7 +79,7 @@ suspend fun RocketChatClient.postMessage( emoji: String? = null, avatar: String? = null, attachments: List? = null -): Message = withContext(CommonPool) { +): Message = withContext(Dispatchers.IO) { val payload = PostMessagePayload(roomId, text, alias, emoji, avatar, attachments) val adapter = moshi.adapter(PostMessagePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -102,7 +102,7 @@ suspend fun RocketChatClient.postMessage( * @return The updated Message object. */ suspend fun RocketChatClient.updateMessage(roomId: String, messageId: String, text: String): Message = - withContext(CommonPool) { + withContext(Dispatchers.IO) { val payload = PostMessagePayload(roomId, text, null, null, null, null, messageId) val adapter = moshi.adapter(PostMessagePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -128,7 +128,7 @@ suspend fun RocketChatClient.deleteMessage( roomId: String, msgId: String, asUser: Boolean = false -): DeleteResult = withContext(CommonPool) { +): DeleteResult = withContext(Dispatchers.IO) { val payload = DeletePayload(roomId, msgId, asUser) val adapter = moshi.adapter(DeletePayload::class.java) val payloadBody = adapter.toJson(payload) @@ -147,7 +147,7 @@ suspend fun RocketChatClient.deleteMessage( * @param messageId The message id to star. */ suspend fun RocketChatClient.starMessage(messageId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = FormBody.Builder().add("messageId", messageId).build() val httpUrl = requestUrl(restUrl, "chat.starMessage").build() @@ -164,7 +164,7 @@ suspend fun RocketChatClient.starMessage(messageId: String) { * @param messageId The message id to unstar. */ suspend fun RocketChatClient.unstarMessage(messageId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = FormBody.Builder().add("messageId", messageId).build() val httpUrl = requestUrl(restUrl, "chat.unStarMessage").build() @@ -181,7 +181,7 @@ suspend fun RocketChatClient.unstarMessage(messageId: String) { * @param messageId The message id to pin. */ suspend fun RocketChatClient.pinMessage(messageId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = FormBody.Builder().add("messageId", messageId).build() val httpUrl = requestUrl(restUrl, "chat.pinMessage").build() @@ -198,7 +198,7 @@ suspend fun RocketChatClient.pinMessage(messageId: String) { * @param messageId The message id to unpin. */ suspend fun RocketChatClient.unpinMessage(messageId: String) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = FormBody.Builder().add("messageId", messageId).build() val httpUrl = requestUrl(restUrl, "chat.unPinMessage").build() @@ -216,7 +216,7 @@ suspend fun RocketChatClient.unpinMessage(messageId: String) { * @param messageId The message id to reaction refers. * @param emoji The emoji to react with or clear. */ -suspend fun RocketChatClient.toggleReaction(messageId: String, emoji: String): Boolean = withContext(CommonPool) { +suspend fun RocketChatClient.toggleReaction(messageId: String, emoji: String): Boolean = withContext(Dispatchers.IO) { val url = requestUrl(restUrl, "chat.react").build() val payload = ReactionPayload(messageId, emoji) @@ -245,7 +245,7 @@ suspend fun RocketChatClient.uploadFile( msg: String = "", description: String = "" ) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( @@ -268,7 +268,7 @@ suspend fun RocketChatClient.uploadFile( description: String = "", inputStreamProvider: () -> InputStream? ) { - withContext(CommonPool) { + withContext(Dispatchers.IO) { val body = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( @@ -297,7 +297,7 @@ suspend fun RocketChatClient.messages( roomType: RoomType, offset: Long, count: Long -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl( restUrl, getRestApiMethodNameByRoomType(roomType, "messages") @@ -324,7 +324,7 @@ suspend fun RocketChatClient.history( count: Long = 50, oldest: String? = null, latest: String? = null -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, getRestApiMethodNameByRoomType(roomType, "history")).apply { addQueryParameter("roomId", roomId) addQueryParameter("count", count.toString()) @@ -352,7 +352,7 @@ suspend fun RocketChatClient.getMessageReadReceipts( count: Long = 50, oldest: String? = null, latest: String? = null -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "chat.getMessageReadReceipts").apply { addQueryParameter("messageId", messageId) addQueryParameter("count", count.toString()) @@ -384,7 +384,7 @@ suspend fun RocketChatClient.getMessageReadReceipts( suspend fun RocketChatClient.reportMessage( messageId: String, description: String -): Boolean = withContext(CommonPool) { +): Boolean = withContext(Dispatchers.IO) { val payload = MessageReportPayload(messageId = messageId, description = description) val adapter = moshi.adapter(MessageReportPayload::class.java) val payloadBody = adapter.toJson(payload) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Permissions.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Permissions.kt index d6ce166e..700ea526 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Permissions.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Permissions.kt @@ -3,15 +3,15 @@ package chat.rocket.core.internal.rest import chat.rocket.core.RocketChatClient import chat.rocket.core.model.Permission import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext /** * Request all permissions associated to each role at current server. * * @return A list containing all permission types and their associated roles. */ -suspend fun RocketChatClient.permissions(): List = withContext(CommonPool) { +suspend fun RocketChatClient.permissions(): List = withContext(Dispatchers.IO) { val url = requestUrl(restUrl, "permissions").build() val request = requestBuilderForAuthenticatedMethods(url).get().build() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Push.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Push.kt index b87f9197..a0fbe571 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Push.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Push.kt @@ -7,11 +7,11 @@ import chat.rocket.core.internal.model.PushRegistrationPayload import chat.rocket.core.internal.model.PushUnregistrationPayload import chat.rocket.core.model.PushToken import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.RequestBody -suspend fun RocketChatClient.registerPushToken(token: String) = withContext(CommonPool) { +suspend fun RocketChatClient.registerPushToken(token: String) = withContext(Dispatchers.IO) { val payload = PushRegistrationPayload(value = token) val adapter = moshi.adapter(PushRegistrationPayload::class.java) @@ -26,7 +26,7 @@ suspend fun RocketChatClient.registerPushToken(token: String) = withContext(Comm handleRestCall>(request, type).result() } -suspend fun RocketChatClient.unregisterPushToken(token: String) = withContext(CommonPool) { +suspend fun RocketChatClient.unregisterPushToken(token: String) = withContext(Dispatchers.IO) { val payload = PushUnregistrationPayload(token) val adapter = moshi.adapter(PushUnregistrationPayload::class.java) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/RestClient.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/RestClient.kt index 231349b2..f856eb9f 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/RestClient.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/RestClient.kt @@ -14,8 +14,8 @@ import chat.rocket.common.util.Logger import chat.rocket.core.RocketChatClient import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import kotlinx.coroutines.experimental.CancellableContinuation -import kotlinx.coroutines.experimental.suspendCancellableCoroutine +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.Call import okhttp3.Callback import okhttp3.HttpUrl @@ -26,6 +26,8 @@ import okhttp3.Response import java.io.IOException import java.lang.reflect.Type import java.util.concurrent.TimeUnit +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException internal fun getRestApiMethodNameByRoomType(roomType: RoomType, method: String): String { return when (roomType) { @@ -44,6 +46,14 @@ internal fun requestUrl(baseUrl: HttpUrl, method: String): HttpUrl.Builder { .addPathSegment(method) } +internal fun requestUrlForVideoConference(baseUrl: HttpUrl, method: String): HttpUrl.Builder { + return baseUrl.newBuilder() + .addPathSegment("api") + .addPathSegment("v1") + .addPathSegment("video-conference") + .addPathSegment(method) +} + internal fun RocketChatClient.requestBuilder(httpUrl: HttpUrl): Request.Builder = Request.Builder() .url(httpUrl) @@ -116,8 +126,8 @@ internal suspend fun RocketChatClient.handleRequest( val client = ensureClient(largeFile, allowRedirects) client.newCall(request).enqueue(callback) - continuation.invokeOnCompletion { - if (continuation.isCancelled) client.cancel(request.tag()) + continuation.invokeOnCancellation { + client.cancel(request.tag()) } } @@ -152,7 +162,6 @@ internal fun processCallbackError( logger: Logger, allowRedirects: Boolean = true ): RocketChatException { - var exception: RocketChatException try { if (response.isRedirect && !allowRedirects) { diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Server.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Server.kt index bc39618b..0e4d4e83 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Server.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Server.kt @@ -7,11 +7,11 @@ import chat.rocket.core.internal.model.ConfigurationsPayload import chat.rocket.core.internal.model.ServerInfoResponse import chat.rocket.core.model.Value import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.HttpUrl -suspend fun RocketChatClient.serverInfo(): ServerInfo = withContext(CommonPool) { +suspend fun RocketChatClient.serverInfo(): ServerInfo = withContext(Dispatchers.IO) { val url = restUrl.newBuilder() .addPathSegment("api") .addPathSegment("info") @@ -37,7 +37,7 @@ private fun HttpUrl.baseUrl(): HttpUrl { .build() } -suspend fun RocketChatClient.configurations(): Map> = withContext(CommonPool) { +suspend fun RocketChatClient.configurations(): Map> = withContext(Dispatchers.IO) { val url = restUrl.newBuilder().apply { addPathSegment("api") addPathSegment("v1") @@ -71,7 +71,7 @@ suspend fun RocketChatClient.configurations(): Map> * * @since 0.63.0 */ -suspend fun RocketChatClient.settingsOauth(): SettingsOauth = withContext(CommonPool) { +suspend fun RocketChatClient.settingsOauth(): SettingsOauth = withContext(Dispatchers.IO) { val url = restUrl.newBuilder() .addPathSegment("api") .addPathSegment("v1") @@ -83,7 +83,7 @@ suspend fun RocketChatClient.settingsOauth(): SettingsOauth = withContext(Common handleRestCall(request, SettingsOauth::class.java) } -suspend fun RocketChatClient.settings(vararg filter: String): Map> = withContext(CommonPool) { +suspend fun RocketChatClient.settings(vararg filter: String): Map> = withContext(Dispatchers.IO) { val url = restUrl.newBuilder().apply { addPathSegment("api") addPathSegment("v1") diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/Spotlight.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/Spotlight.kt index 044551f0..dbc0dafe 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/Spotlight.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/Spotlight.kt @@ -2,10 +2,10 @@ package chat.rocket.core.internal.rest import chat.rocket.core.RocketChatClient import chat.rocket.core.model.SpotlightResult -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext -suspend fun RocketChatClient.spotlight(query: String): SpotlightResult = withContext(CommonPool) { +suspend fun RocketChatClient.spotlight(query: String): SpotlightResult = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "spotlight") .addQueryParameter("query", query) .build() diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/User.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/User.kt index 969ca0e8..99eac2f0 100644 --- a/core/src/main/kotlin/chat/rocket/core/internal/rest/User.kt +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/User.kt @@ -20,9 +20,9 @@ import chat.rocket.core.model.Removed import chat.rocket.core.model.UserRole import chat.rocket.core.model.Room import com.squareup.moshi.Types -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.async -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.withContext import okhttp3.MediaType import okhttp3.MultipartBody import okhttp3.RequestBody @@ -215,7 +215,7 @@ suspend fun RocketChatClient.chatRooms( * * @return UserRole object specifying current user roles. */ -suspend fun RocketChatClient.roles(): UserRole = withContext(CommonPool) { +suspend fun RocketChatClient.roles(): UserRole = withContext(Dispatchers.IO) { val httpUrl = requestUrl(restUrl, "user.roles").build() val request = requestBuilderForAuthenticatedMethods(httpUrl).get().build() return@withContext handleRestCall(request, UserRole::class.java) diff --git a/core/src/main/kotlin/chat/rocket/core/internal/rest/VideoConference.kt b/core/src/main/kotlin/chat/rocket/core/internal/rest/VideoConference.kt new file mode 100644 index 00000000..a6db8214 --- /dev/null +++ b/core/src/main/kotlin/chat/rocket/core/internal/rest/VideoConference.kt @@ -0,0 +1,26 @@ +package chat.rocket.core.internal.rest + +import chat.rocket.core.RocketChatClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.FormBody + +/** + * Updates the jitsi timeout. + * + * REMARK Jitsi timeout needs to be called every 10 seconds to make sure the call is not ended and is available to web users. + * + * @param roomId the room id of where the jitsi timeout needs to be updated + * @since Rocket.Chat Server version 0.74.0 + */ +suspend fun RocketChatClient.updateJitsiTimeout(roomId: String) { + withContext(Dispatchers.IO) { + val body = FormBody.Builder().add("roomId", roomId).build() + + val httpUrl = requestUrlForVideoConference(restUrl, "jitsi.update-timeout").build() + + val request = requestBuilderForAuthenticatedMethods(httpUrl).post(body).build() + + handleRestCall(request, Any::class.java) + } +} diff --git a/core/src/main/kotlin/chat/rocket/core/model/ChatRoom.kt b/core/src/main/kotlin/chat/rocket/core/model/ChatRoom.kt index d50079fb..4232b8fb 100644 --- a/core/src/main/kotlin/chat/rocket/core/model/ChatRoom.kt +++ b/core/src/main/kotlin/chat/rocket/core/model/ChatRoom.kt @@ -9,8 +9,8 @@ import chat.rocket.core.internal.model.Subscription import chat.rocket.core.internal.realtime.subscribeRoomMessages import chat.rocket.core.internal.rest.history import chat.rocket.core.internal.rest.messages -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.withContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext data class ChatRoom( override val id: String, @@ -82,7 +82,7 @@ data class ChatRoom( suspend fun ChatRoom.messages( offset: Long = 0, count: Long = 50 -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { return@withContext client.messages(id, type, offset, count) } @@ -90,7 +90,7 @@ suspend fun ChatRoom.history( count: Long = 50, oldest: String? = null, latest: String? = null -): PagedResult> = withContext(CommonPool) { +): PagedResult> = withContext(Dispatchers.IO) { return@withContext client.history(id, type, count, oldest, latest) } diff --git a/core/src/main/kotlin/chat/rocket/core/model/Message.kt b/core/src/main/kotlin/chat/rocket/core/model/Message.kt index 94d8c4d4..3f441c90 100644 --- a/core/src/main/kotlin/chat/rocket/core/model/Message.kt +++ b/core/src/main/kotlin/chat/rocket/core/model/Message.kt @@ -51,12 +51,13 @@ data class Message( val reactions: Reactions? = null, val role: String? = null, @JsonDefaultValueBoolean(true) - override val synced: Boolean = true, //TODO: Remove after we have a db + override val synced: Boolean = true, // TODO: Remove after we have a db val unread: Boolean? = null ) : BaseMessage @FallbackSealedClass(name = "Unspecified", fieldName = "rawType") sealed class MessageType { + @Json(name = "r") class RoomNameChanged : MessageType() @@ -96,6 +97,9 @@ sealed class MessageType { @Json(name = "room_changed_privacy") class RoomChangedPrivacy : MessageType() + @Json(name = "jitsi_call_started") + class JitsiCallStarted : MessageType() + class Unspecified(val rawType: String) : MessageType() } @@ -114,6 +118,7 @@ fun MessageType?.asString(): String? { is MessageType.SubscriptionRoleAdded -> "subscription-role-added" is MessageType.SubscriptionRoleRemoved -> "subscription-role-removed" is MessageType.RoomChangedPrivacy -> "room_changed_privacy" + is MessageType.JitsiCallStarted -> "jitsi_call_started" else -> null } } @@ -130,6 +135,7 @@ fun Message.isSystemMessage() = when (type) { is MessageType.SubscriptionRoleAdded, is MessageType.SubscriptionRoleRemoved, is MessageType.RoomChangedPrivacy, + is MessageType.JitsiCallStarted, is MessageType.MessagePinned -> true else -> false } @@ -149,6 +155,7 @@ fun messageTypeOf(type: String?): MessageType? { "subscription-role-added" -> MessageType.SubscriptionRoleAdded() "subscription-role-removed" -> MessageType.SubscriptionRoleAdded() "room_changed_privacy" -> MessageType.RoomChangedPrivacy() + "jitsi_call_started" -> MessageType.JitsiCallStarted() null -> null else -> MessageType.Unspecified(type) } diff --git a/core/src/main/kotlin/chat/rocket/core/model/url/Meta.kt b/core/src/main/kotlin/chat/rocket/core/model/url/Meta.kt index e4eec7a2..1576af9f 100644 --- a/core/src/main/kotlin/chat/rocket/core/model/url/Meta.kt +++ b/core/src/main/kotlin/chat/rocket/core/model/url/Meta.kt @@ -66,7 +66,7 @@ class MetaJsonAdapter(moshi: Moshi) : JsonAdapter() { } override fun toJson(writer: JsonWriter, value: Meta?) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } companion object { diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/ChannelTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/ChannelTest.kt index 79e7445f..93f40199 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/ChannelTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/ChannelTest.kt @@ -9,7 +9,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.CoreMatchers.instanceOf import org.hamcrest.MatcherAssert.assertThat diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/ChatRoomTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/ChatRoomTest.kt index 7d1b479b..7f3e8327 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/ChatRoomTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/ChatRoomTest.kt @@ -8,7 +8,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.junit.Before import org.junit.Test diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/CommandsTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/CommandsTest.kt index 9f4748e2..8d1d078a 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/CommandsTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/CommandsTest.kt @@ -6,7 +6,7 @@ import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import chat.rocket.core.model.Command import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.MatcherAssert.assertThat import org.junit.After diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/Constants.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/Constants.kt index 137f3a20..8731b877 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/Constants.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/Constants.kt @@ -10,25 +10,33 @@ const val LOGOUT_SUCCESS = "{ \"status\": \"success\", \"data\": { \"message\": const val USER_NOT_FOUND_ERROR = "{\"status\": \"false\",\"message\": \"User not found\"}" -const val USER_REGISTER_SUCCESS = "{\"user\":{\"_id\":\"userId\",\"createdAt\":\"2017-11-07T15:59:50.432Z\",\"services\":{\"password\":{\"bcrypt\":\"bcrypt-password\"},\"email\":{\"verificationTokens\":[{\"token\":\"verificationToken\",\"address\":\"test@email.com\",\"when\":\"2017-11-07T15:59:50.457Z\"}]}},\"emails\":[{\"address\":\"test@email.com\",\"verified\":false}],\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Test User\",\"_updatedAt\":\"2017-11-07T15:59:51.144Z\",\"roles\":[\"user\"],\"username\":\"testuser\"},\"success\":true}" -const val USER_UPDATE_SUCCESS = "{\"user\":{\"_id\":\"userId\",\"createdAt\":\"2017-11-07T15:59:50.432Z\",\"services\":{\"password\":{\"bcrypt\":\"new-bcrypt-password\"},\"email\":{\"verificationTokens\":[{\"token\":\"verificationToken\",\"address\":\"test@email.com\",\"when\":\"2017-11-07T15:59:50.457Z\"}]}},\"emails\":[{\"address\":\"test@email.com\",\"verified\":false}],\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"New name\",\"_updatedAt\":\"2017-11-07T15:59:51.144Z\",\"roles\":[\"user\"],\"username\":\"new-username\"},\"success\":true}" +const val USER_REGISTER_SUCCESS = + "{\"user\":{\"_id\":\"userId\",\"createdAt\":\"2017-11-07T15:59:50.432Z\",\"services\":{\"password\":{\"bcrypt\":\"bcrypt-password\"},\"email\":{\"verificationTokens\":[{\"token\":\"verificationToken\",\"address\":\"test@email.com\",\"when\":\"2017-11-07T15:59:50.457Z\"}]}},\"emails\":[{\"address\":\"test@email.com\",\"verified\":false}],\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Test User\",\"_updatedAt\":\"2017-11-07T15:59:51.144Z\",\"roles\":[\"user\"],\"username\":\"testuser\"},\"success\":true}" +const val USER_UPDATE_SUCCESS = + "{\"user\":{\"_id\":\"userId\",\"createdAt\":\"2017-11-07T15:59:50.432Z\",\"services\":{\"password\":{\"bcrypt\":\"new-bcrypt-password\"},\"email\":{\"verificationTokens\":[{\"token\":\"verificationToken\",\"address\":\"test@email.com\",\"when\":\"2017-11-07T15:59:50.457Z\"}]}},\"emails\":[{\"address\":\"test@email.com\",\"verified\":false}],\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"New name\",\"_updatedAt\":\"2017-11-07T15:59:51.144Z\",\"roles\":[\"user\"],\"username\":\"new-username\"},\"success\":true}" const val FAIL_EMAIL_IN_USE = "{\"success\":false,\"error\":\"Email already exists. [403]\",\"errorType\":403}" -const val FAIL_USER_IN_USE = "{\"success\":false,\"error\":\"testuser is already in use :( [error-field-unavailable]\",\"errorType\":\"error-field-unavailable\"}" +const val FAIL_USER_IN_USE = + "{\"success\":false,\"error\":\"testuser is already in use :( [error-field-unavailable]\",\"errorType\":\"error-field-unavailable\"}" -const val ME_SUCCESS = "{\"_id\":\"userid\",\"name\":\"testuser\",\"emails\":[{\"address\":\"testuser@test.com\",\"verified\":false}],\"status\":\"offline\",\"statusConnection\":\"offline\",\"username\":\"testuser\",\"utcOffset\":-3,\"active\":true,\"success\":true}" +const val ME_SUCCESS = + "{\"_id\":\"userid\",\"name\":\"testuser\",\"emails\":[{\"address\":\"testuser@test.com\",\"verified\":false}],\"status\":\"offline\",\"statusConnection\":\"offline\",\"username\":\"testuser\",\"utcOffset\":-3,\"active\":true,\"success\":true}" const val ME_UNAUTHORIZED = "{\"status\":\"error\",\"message\":\"You must be logged in to do this.\"}" -const val USER_SUBSCRIPTIONS_OK = "{\"channels\":[{\"_id\":\"GENERAL\",\"ts\":\"2017-10-20T12:51:33.778Z\",\"t\":\"c\",\"name\":\"general\",\"msgs\":23,\"default\":true,\"_updatedAt\":\"2017-11-17T16:16:04.654Z\",\"lm\":\"2017-11-06T16:02:00.611Z\",\"usernames\":[\"testuser\",\"testuser1\"]}],\"offset\":0,\"count\":1,\"total\":1,\"success\":true}" +const val USER_SUBSCRIPTIONS_OK = + "{\"channels\":[{\"_id\":\"GENERAL\",\"ts\":\"2017-10-20T12:51:33.778Z\",\"t\":\"c\",\"name\":\"general\",\"msgs\":23,\"default\":true,\"_updatedAt\":\"2017-11-17T16:16:04.654Z\",\"lm\":\"2017-11-06T16:02:00.611Z\",\"usernames\":[\"testuser\",\"testuser1\"]}],\"offset\":0,\"count\":1,\"total\":1,\"success\":true}" -const val SEND_MESSAGE_OK_UPDATED = "{\"ts\":1511443964815,\"channel\":\"GENERAL\",\"message\":{\"alias\":\"TestingAlias\",\"msg\":\"Updating a message previously sent to #general\",\"parseUrls\":true,\"groupable\":false,\"avatar\":\"https://avatars2.githubusercontent.com/u/224255?s=88&v=4\",\"ts\":\"2017-11-23T13:32:44.798Z\",\"u\":{\"_id\":\"userId\",\"username\":\"testuser\",\"name\":\"testuser\"},\"rid\":\"GENERAL\",\"channels\":[{\"_id\":\"GENERAL\",\"name\":\"general\"}],\"_updatedAt\":\"2017-11-23T13:32:44.808Z\",\"_id\":\"messageId\"},\"success\":true}" +const val SEND_MESSAGE_OK_UPDATED = + "{\"ts\":1511443964815,\"channel\":\"GENERAL\",\"message\":{\"alias\":\"TestingAlias\",\"msg\":\"Updating a message previously sent to #general\",\"parseUrls\":true,\"groupable\":false,\"avatar\":\"https://avatars2.githubusercontent.com/u/224255?s=88&v=4\",\"ts\":\"2017-11-23T13:32:44.798Z\",\"u\":{\"_id\":\"userId\",\"username\":\"testuser\",\"name\":\"testuser\"},\"rid\":\"GENERAL\",\"channels\":[{\"_id\":\"GENERAL\",\"name\":\"general\"}],\"_updatedAt\":\"2017-11-23T13:32:44.808Z\",\"_id\":\"messageId\"},\"success\":true}" -const val SEND_MESSAGE_OK = "{\"ts\":1511443964815,\"channel\":\"GENERAL\",\"message\":{\"alias\":\"TestingAlias\",\"msg\":\"Sending message from SDK to #general and @here with url https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK/\",\"parseUrls\":true,\"groupable\":false,\"avatar\":\"https://avatars2.githubusercontent.com/u/224255?s=88&v=4\",\"ts\":\"2017-11-23T13:32:44.798Z\",\"u\":{\"_id\":\"userId\",\"username\":\"testuser\",\"name\":\"testuser\"},\"rid\":\"GENERAL\",\"urls\":[{\"url\":\"https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK/\"}],\"mentions\":[{\"_id\":\"here\",\"username\":\"here\"}],\"channels\":[{\"_id\":\"GENERAL\",\"name\":\"general\"}],\"_updatedAt\":\"2017-11-23T13:32:44.808Z\",\"_id\":\"messageId\"},\"success\":true}" +const val SEND_MESSAGE_OK = + "{\"ts\":1511443964815,\"channel\":\"GENERAL\",\"message\":{\"alias\":\"TestingAlias\",\"msg\":\"Sending message from SDK to #general and @here with url https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK/\",\"parseUrls\":true,\"groupable\":false,\"avatar\":\"https://avatars2.githubusercontent.com/u/224255?s=88&v=4\",\"ts\":\"2017-11-23T13:32:44.798Z\",\"u\":{\"_id\":\"userId\",\"username\":\"testuser\",\"name\":\"testuser\"},\"rid\":\"GENERAL\",\"urls\":[{\"url\":\"https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK/\"}],\"mentions\":[{\"_id\":\"here\",\"username\":\"here\"}],\"channels\":[{\"_id\":\"GENERAL\",\"name\":\"general\"}],\"_updatedAt\":\"2017-11-23T13:32:44.808Z\",\"_id\":\"messageId\"},\"success\":true}" const val DELETE_MESSAGE_OK = "{\"_id\":\"messageId\",\"ts\":1511443964815,\"success\":true}" // TODO: Add expected return. -const val MEMBERS_OK = "{\"members\":[{\"_id\":\"userid\",\"username\":\"filipedelimabrito\",\"name\":\"Filipe de Lima Brito\",\"status\":\"online\",\"utcOffset\":-6}],\"count\":1,\"offset\":0,\"total\":1,\"success\":true}" +const val MEMBERS_OK = + "{\"members\":[{\"_id\":\"userid\",\"username\":\"filipedelimabrito\",\"name\":\"Filipe de Lima Brito\",\"status\":\"online\",\"utcOffset\":-6}],\"count\":1,\"offset\":0,\"total\":1,\"success\":true}" const val MENTIONS_OK = "{\n" + " \"mentions\": [\n" + @@ -79,9 +87,11 @@ const val MESSAGES_OK = "{\n" + " \"success\": true\n" + "}" -const val ROOMS_OK = "{\"update\":[{\"_id\":\"cBD6dHc7oBvGjkruMrocket.cat\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMnGgokxmGQtrwe4qyh\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMkcqDE6baR7Y5gHLEf\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMw4XQhPWoSCN29ZtQG\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMrdDGZc75Grpnd5Tdf\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"7fw6XRQWHi4Ak3zj4cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-31T19:59:25.629Z\"},{\"_id\":\"MHNCPQyQnzdjRPiuRcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-22T13:06:34.726Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMnBe2T2HXC6KEyzK2P\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"G75tcPe8QHAL56BZ4cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"YdpayxcMhWFGKRZb3cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"nNT3JREJNY8j7uFHX\",\"name\":\"android-dev-internal\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"_updatedAt\":\"2017-09-06T12:43:31.943Z\",\"archived\":true,\"customFields\":{},\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMjrnR99viqXELp4XYn\",\"t\":\"d\",\"_updatedAt\":\"2017-11-23T17:59:59.070Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMg9vNPgp6C4nDpSp8W\",\"t\":\"d\",\"_updatedAt\":\"2017-10-02T18:53:45.591Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMkAuTB2QwESvC6XWtB\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMoJWt2aGXP7wo9gPBi\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"N8HuZbMTSeZyZi6wc\",\"name\":\"mobile-native\",\"t\":\"p\",\"u\":{\"_id\":null,\"username\":null},\"topic\":\"Channel to discuss common functionality between iOS and Android - See [Spec](https://docs.google.com/spreadsheets/d/1SvHnjpI6TFes89VgwrUUwB0T0NvEkJQmoM9Vi-XqxXg/edit?usp=drive_web)\",\"_updatedAt\":\"2017-09-06T12:43:15.867Z\",\"archived\":true,\"jitsiTimeout\":\"2016-11-18T11:08:35.225Z\",\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMrXNAqsj2LJCCyqE6D\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMosnQaABmyfQoadYqW\",\"t\":\"d\",\"_updatedAt\":\"2017-08-28T16:49:10.846Z\"},{\"_id\":\"Cbmjf5XxJoSpQtd6EcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"8WCaFa2Jve4FNjMYacBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-09-29T14:43:54.286Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMuWiyfQkgekhXywvKw\",\"t\":\"d\",\"_updatedAt\":\"2017-12-06T00:24:57.156Z\"},{\"_id\":\"YWPMv8Z33hdQ9h6NkcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"jyki6cZ338aisMsG9\",\"name\":\"movile\",\"t\":\"p\",\"u\":{\"_id\":\"4SFNEydqQhHtj5KkP\",\"username\":\"gabriel.engel\"},\"_updatedAt\":\"2017-10-31T18:11:52.506Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMufcwE9NeH8MKik7AS\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"F6gZmaujtQceMst7TcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-09-18T12:58:55.853Z\"},{\"_id\":\"F3WPrkRCHsQXnkpQE\",\"name\":\"filipedelimabrito-public-channel\",\"fname\":\"filipedelimabrito-public-channel\",\"t\":\"c\",\"u\":{\"_id\":\"8WCaFa2Jve4FNjMYa\",\"username\":\"filipedelimabrito\"},\"_updatedAt\":\"2017-10-09T21:43:31.647Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"Qhyt2tDnJ7H3ELMcC\",\"name\":\"mobile-circleci\",\"fname\":\"mobile-circleci\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"muted\":[\"filipe.brito\",\"leonardo.aramaki\",\"lucio.maciel\",\"matheus.cardoso\"],\"_updatedAt\":\"2017-12-04T11:59:54.417Z\",\"jitsiTimeout\":\"2017-09-12T13:27:19.223Z\",\"customFields\":{},\"ro\":true,\"reactWhenReadOnly\":true},{\"_id\":\"KCEnsZw4GHwcXrRrEcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-26T18:24:02.719Z\"},{\"_id\":\"MZiFvWAfF4RF4AD5ucBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-10T21:22:03.354Z\"},{\"_id\":\"YFGDi4YmQEda4FkPC\",\"name\":\"rocketchat-security\",\"fname\":\"rocketchat-security\",\"t\":\"p\",\"u\":{\"_id\":\"MZiFvWAfF4RF4AD5u\",\"username\":\"rodrigo.nascimento\"},\"_updatedAt\":\"2017-10-11T00:10:14.703Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMj6Ge8FJTqjNyQoJsv\",\"t\":\"d\",\"_updatedAt\":\"2017-10-13T19:27:28.752Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMtTkbX7TdzMceKmCqW\",\"t\":\"d\",\"_updatedAt\":\"2017-11-16T18:57:05.138Z\"},{\"_id\":\"Br5ZisLJ8va98jFBD\",\"name\":\"officevibe\",\"fname\":\"officevibe\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"topic\":\"Officevibe poll answers\",\"_updatedAt\":\"2017-12-21T17:40:33.614Z\",\"description\":\"Here we'll share Officevibe poll answers, so everyone can get to know each other.\",\"customFields\":{},\"ro\":false},{\"_id\":\"3r7JSBtEGaeaPWjsicBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-11-29T14:22:37.266Z\"},{\"_id\":\"FaXMyHqbNJbPq6Ym9cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-05T22:24:13.373Z\"},{\"_id\":\"2B6NWL88MoijfZswt\",\"name\":\"rocket.chat.summit\",\"fname\":\"rocket.chat.summit\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"_updatedAt\":\"2017-12-21T22:45:53.490Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"mSCEim3yGNb2rZhev\",\"name\":\"androidnativeapp\",\"t\":\"c\",\"u\":{\"_id\":\"KdgnfaCiHf2yxPiaX\",\"username\":\"julio.cesar.bueno.cotta\"},\"_updatedAt\":\"2017-12-28T10:03:40.415Z\"},{\"_id\":\"k46YezYaE9jmvi7uM\",\"name\":\"random\",\"t\":\"p\",\"u\":{\"_id\":\"CA57idSqCkvBHHC8w\",\"username\":\"foo-11\"},\"topic\":\"Off-Topic Dumb Stuff\",\"_updatedAt\":\"2017-12-28T10:11:19.956Z\",\"archived\":false,\"jitsiTimeout\":\"2017-11-28T23:09:19.786Z\"},{\"_id\":\"2vmeeZapHrxqWKif2\",\"name\":\"android-native-sdk\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-28T15:13:03.560Z\",\"jitsiTimeout\":\"2017-06-29T04:14:56.812Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"QG6WKaB3YZKzv2ykN\",\"name\":\"important\",\"t\":\"p\",\"u\":{\"_id\":\"4SFNEydqQhHtj5KkP\",\"username\":\"gabriel.engel\"},\"topic\":\"Announcements, Items needing attention, Team wide inquiries, etc. Go to [BambooHR](https://rocketchat.bamboohr.com) for time off requests.\",\"announcement\":\"\",\"_updatedAt\":\"2017-12-28T16:30:11.710Z\",\"jitsiTimeout\":\"2017-11-30T23:01:33.699Z\",\"ro\":false},{\"_id\":\"KK6xPd6zQb5MyEjYbcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-28T17:47:12.789Z\"},{\"_id\":\"Y6587MM9T2ca4m9AP\",\"name\":\"rocketchat-working-on\",\"fname\":\"rocketchat-working-on\",\"t\":\"p\",\"u\":{\"_id\":\"MZiFvWAfF4RF4AD5u\",\"username\":\"rodrigo.nascimento\"},\"topic\":\"The purpose is to keep the rest of the team up-to-date with what you are busy with each day\",\"_updatedAt\":\"2017-12-28T17:49:31.024Z\",\"description\":\"We created this channel for each team member to post what they are working on for they day. The purpose is to keep the rest of the team up-to-date with what you are busy with each day. Keep each post short, don&#39;t talk about what you did yesterday or are doing tomorrow, don&#39;t mention generic things like meetings, emails, todos etc. An informative update will list only a handful of tasks and link to issues or documents.\",\"customFields\":{},\"ro\":false},{\"_id\":\"FATCnDk5egNtRvQfv\",\"name\":\"rocket-dev\",\"t\":\"p\",\"u\":{\"_id\":\"7fw6XRQWHi4Ak3zj4\",\"username\":\"aaron.ogle\"},\"topic\":\"Making an awesome chat platform!\",\"_updatedAt\":\"2017-12-28T17:59:59.545Z\",\"jitsiTimeout\":\"2017-10-04T14:41:15.330Z\"},{\"_id\":\"5KAw6vTLBkSJKefae\",\"name\":\"android-app-rewrite\",\"fname\":\"android-app-rewrite\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-28T17:59:50.506Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"8MyxXwfqeioYwmnnKcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-28T23:51:31.028Z\"},{\"_id\":\"uaNMXwBvMSd8Lt2zG\",\"name\":\"jobs\",\"t\":\"c\",\"u\":{\"_id\":\"LuQZ9zJmsgPX5tJdg\",\"username\":\"Goran\"},\"topic\":\"RC related jobs only. Please use DM or email for followup\",\"_updatedAt\":\"2017-12-29T04:52:08.399Z\"},{\"_id\":\"9fcPiSCwpW8uB6fok\",\"name\":\"iosnativeapp\",\"t\":\"c\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-29T02:32:20.780Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"tn3EiAYecbtXGEBDn\",\"name\":\"mobile-internal\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"topic\":\"Mobile Native Applications\",\"_updatedAt\":\"2017-12-29T13:07:19.181Z\",\"archived\":false,\"jitsiTimeout\":\"2017-09-19T00:38:49.750Z\",\"description\":\"This group is related to all internal Native Mobile development of Rocket.Chat discussions.\",\"customFields\":{},\"ro\":false,\"reactWhenReadOnly\":true},{\"_id\":\"AALrfqnPPNykhvhWo\",\"name\":\"rocketchat-ux\",\"fname\":\"rocketchat-ux\",\"t\":\"p\",\"u\":{\"_id\":\"tTkbX7TdzMceKmCqW\",\"username\":\"arthur.giustina\"},\"_updatedAt\":\"2017-12-29T13:24:13.100Z\",\"jitsiTimeout\":\"2017-11-07T16:57:22.223Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"GENERAL\",\"name\":\"general\",\"t\":\"c\",\"topic\":\"Community support in [#support](https://demo.rocket.chat/channel/support). Discussions in our [forums](https://forums.rocket.chat/). Find jobs in [#jobs](https://demo.rocket.chat/channel/jobs)\",\"announcement\":\"Try our new discussion forums - https://forums.rocket.chat\",\"muted\":[\"geekgonecrazy\"],\"_updatedAt\":\"2017-12-29T13:32:07.017Z\",\"jitsiTimeout\":\"2017-09-15T00:27:28.892Z\",\"default\":true}],\"remove\":[],\"success\":true}\n" +const val ROOMS_OK = + "{\"update\":[{\"_id\":\"cBD6dHc7oBvGjkruMrocket.cat\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMnGgokxmGQtrwe4qyh\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMkcqDE6baR7Y5gHLEf\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMw4XQhPWoSCN29ZtQG\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMrdDGZc75Grpnd5Tdf\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"7fw6XRQWHi4Ak3zj4cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-31T19:59:25.629Z\"},{\"_id\":\"MHNCPQyQnzdjRPiuRcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-22T13:06:34.726Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMnBe2T2HXC6KEyzK2P\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"G75tcPe8QHAL56BZ4cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"YdpayxcMhWFGKRZb3cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"nNT3JREJNY8j7uFHX\",\"name\":\"android-dev-internal\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"_updatedAt\":\"2017-09-06T12:43:31.943Z\",\"archived\":true,\"customFields\":{},\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMjrnR99viqXELp4XYn\",\"t\":\"d\",\"_updatedAt\":\"2017-11-23T17:59:59.070Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMg9vNPgp6C4nDpSp8W\",\"t\":\"d\",\"_updatedAt\":\"2017-10-02T18:53:45.591Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMkAuTB2QwESvC6XWtB\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMoJWt2aGXP7wo9gPBi\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"N8HuZbMTSeZyZi6wc\",\"name\":\"mobile-native\",\"t\":\"p\",\"u\":{\"_id\":null,\"username\":null},\"topic\":\"Channel to discuss common functionality between iOS and Android - See [Spec](https://docs.google.com/spreadsheets/d/1SvHnjpI6TFes89VgwrUUwB0T0NvEkJQmoM9Vi-XqxXg/edit?usp=drive_web)\",\"_updatedAt\":\"2017-09-06T12:43:15.867Z\",\"archived\":true,\"jitsiTimeout\":\"2016-11-18T11:08:35.225Z\",\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMrXNAqsj2LJCCyqE6D\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMosnQaABmyfQoadYqW\",\"t\":\"d\",\"_updatedAt\":\"2017-08-28T16:49:10.846Z\"},{\"_id\":\"Cbmjf5XxJoSpQtd6EcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"8WCaFa2Jve4FNjMYacBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-09-29T14:43:54.286Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMuWiyfQkgekhXywvKw\",\"t\":\"d\",\"_updatedAt\":\"2017-12-06T00:24:57.156Z\"},{\"_id\":\"YWPMv8Z33hdQ9h6NkcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"jyki6cZ338aisMsG9\",\"name\":\"movile\",\"t\":\"p\",\"u\":{\"_id\":\"4SFNEydqQhHtj5KkP\",\"username\":\"gabriel.engel\"},\"_updatedAt\":\"2017-10-31T18:11:52.506Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMufcwE9NeH8MKik7AS\",\"t\":\"d\",\"_updatedAt\":\"2017-08-22T18:20:11.890Z\"},{\"_id\":\"F6gZmaujtQceMst7TcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-09-18T12:58:55.853Z\"},{\"_id\":\"F3WPrkRCHsQXnkpQE\",\"name\":\"filipedelimabrito-public-channel\",\"fname\":\"filipedelimabrito-public-channel\",\"t\":\"c\",\"u\":{\"_id\":\"8WCaFa2Jve4FNjMYa\",\"username\":\"filipedelimabrito\"},\"_updatedAt\":\"2017-10-09T21:43:31.647Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"Qhyt2tDnJ7H3ELMcC\",\"name\":\"mobile-circleci\",\"fname\":\"mobile-circleci\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"muted\":[\"filipe.brito\",\"leonardo.aramaki\",\"lucio.maciel\",\"matheus.cardoso\"],\"_updatedAt\":\"2017-12-04T11:59:54.417Z\",\"jitsiTimeout\":\"2017-09-12T13:27:19.223Z\",\"customFields\":{},\"ro\":true,\"reactWhenReadOnly\":true},{\"_id\":\"KCEnsZw4GHwcXrRrEcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-26T18:24:02.719Z\"},{\"_id\":\"MZiFvWAfF4RF4AD5ucBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-10-10T21:22:03.354Z\"},{\"_id\":\"YFGDi4YmQEda4FkPC\",\"name\":\"rocketchat-security\",\"fname\":\"rocketchat-security\",\"t\":\"p\",\"u\":{\"_id\":\"MZiFvWAfF4RF4AD5u\",\"username\":\"rodrigo.nascimento\"},\"_updatedAt\":\"2017-10-11T00:10:14.703Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"cBD6dHc7oBvGjkruMj6Ge8FJTqjNyQoJsv\",\"t\":\"d\",\"_updatedAt\":\"2017-10-13T19:27:28.752Z\"},{\"_id\":\"cBD6dHc7oBvGjkruMtTkbX7TdzMceKmCqW\",\"t\":\"d\",\"_updatedAt\":\"2017-11-16T18:57:05.138Z\"},{\"_id\":\"Br5ZisLJ8va98jFBD\",\"name\":\"officevibe\",\"fname\":\"officevibe\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"topic\":\"Officevibe poll answers\",\"_updatedAt\":\"2017-12-21T17:40:33.614Z\",\"description\":\"Here we'll share Officevibe poll answers, so everyone can get to know each other.\",\"customFields\":{},\"ro\":false},{\"_id\":\"3r7JSBtEGaeaPWjsicBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-11-29T14:22:37.266Z\"},{\"_id\":\"FaXMyHqbNJbPq6Ym9cBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-05T22:24:13.373Z\"},{\"_id\":\"2B6NWL88MoijfZswt\",\"name\":\"rocket.chat.summit\",\"fname\":\"rocket.chat.summit\",\"t\":\"p\",\"u\":{\"_id\":\"jrnR99viqXELp4XYn\",\"username\":\"marcelo.schmidt\"},\"_updatedAt\":\"2017-12-21T22:45:53.490Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"mSCEim3yGNb2rZhev\",\"name\":\"androidnativeapp\",\"t\":\"c\",\"u\":{\"_id\":\"KdgnfaCiHf2yxPiaX\",\"username\":\"julio.cesar.bueno.cotta\"},\"_updatedAt\":\"2017-12-28T10:03:40.415Z\"},{\"_id\":\"k46YezYaE9jmvi7uM\",\"name\":\"random\",\"t\":\"p\",\"u\":{\"_id\":\"CA57idSqCkvBHHC8w\",\"username\":\"foo-11\"},\"topic\":\"Off-Topic Dumb Stuff\",\"_updatedAt\":\"2017-12-28T10:11:19.956Z\",\"archived\":false,\"jitsiTimeout\":\"2017-11-28T23:09:19.786Z\"},{\"_id\":\"2vmeeZapHrxqWKif2\",\"name\":\"android-native-sdk\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-28T15:13:03.560Z\",\"jitsiTimeout\":\"2017-06-29T04:14:56.812Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"QG6WKaB3YZKzv2ykN\",\"name\":\"important\",\"t\":\"p\",\"u\":{\"_id\":\"4SFNEydqQhHtj5KkP\",\"username\":\"gabriel.engel\"},\"topic\":\"Announcements, Items needing attention, Team wide inquiries, etc. Go to [BambooHR](https://rocketchat.bamboohr.com) for time off requests.\",\"announcement\":\"\",\"_updatedAt\":\"2017-12-28T16:30:11.710Z\",\"jitsiTimeout\":\"2017-11-30T23:01:33.699Z\",\"ro\":false},{\"_id\":\"KK6xPd6zQb5MyEjYbcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-28T17:47:12.789Z\"},{\"_id\":\"Y6587MM9T2ca4m9AP\",\"name\":\"rocketchat-working-on\",\"fname\":\"rocketchat-working-on\",\"t\":\"p\",\"u\":{\"_id\":\"MZiFvWAfF4RF4AD5u\",\"username\":\"rodrigo.nascimento\"},\"topic\":\"The purpose is to keep the rest of the team up-to-date with what you are busy with each day\",\"_updatedAt\":\"2017-12-28T17:49:31.024Z\",\"description\":\"We created this channel for each team member to post what they are working on for they day. The purpose is to keep the rest of the team up-to-date with what you are busy with each day. Keep each post short, don&#39;t talk about what you did yesterday or are doing tomorrow, don&#39;t mention generic things like meetings, emails, todos etc. An informative update will list only a handful of tasks and link to issues or documents.\",\"customFields\":{},\"ro\":false},{\"_id\":\"FATCnDk5egNtRvQfv\",\"name\":\"rocket-dev\",\"t\":\"p\",\"u\":{\"_id\":\"7fw6XRQWHi4Ak3zj4\",\"username\":\"aaron.ogle\"},\"topic\":\"Making an awesome chat platform!\",\"_updatedAt\":\"2017-12-28T17:59:59.545Z\",\"jitsiTimeout\":\"2017-10-04T14:41:15.330Z\"},{\"_id\":\"5KAw6vTLBkSJKefae\",\"name\":\"android-app-rewrite\",\"fname\":\"android-app-rewrite\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-28T17:59:50.506Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"8MyxXwfqeioYwmnnKcBD6dHc7oBvGjkruM\",\"t\":\"d\",\"_updatedAt\":\"2017-12-28T23:51:31.028Z\"},{\"_id\":\"uaNMXwBvMSd8Lt2zG\",\"name\":\"jobs\",\"t\":\"c\",\"u\":{\"_id\":\"LuQZ9zJmsgPX5tJdg\",\"username\":\"Goran\"},\"topic\":\"RC related jobs only. Please use DM or email for followup\",\"_updatedAt\":\"2017-12-29T04:52:08.399Z\"},{\"_id\":\"9fcPiSCwpW8uB6fok\",\"name\":\"iosnativeapp\",\"t\":\"c\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"_updatedAt\":\"2017-12-29T02:32:20.780Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"tn3EiAYecbtXGEBDn\",\"name\":\"mobile-internal\",\"t\":\"p\",\"u\":{\"_id\":\"MHNCPQyQnzdjRPiuR\",\"username\":\"rafael.kellermann\"},\"topic\":\"Mobile Native Applications\",\"_updatedAt\":\"2017-12-29T13:07:19.181Z\",\"archived\":false,\"jitsiTimeout\":\"2017-09-19T00:38:49.750Z\",\"description\":\"This group is related to all internal Native Mobile development of Rocket.Chat discussions.\",\"customFields\":{},\"ro\":false,\"reactWhenReadOnly\":true},{\"_id\":\"AALrfqnPPNykhvhWo\",\"name\":\"rocketchat-ux\",\"fname\":\"rocketchat-ux\",\"t\":\"p\",\"u\":{\"_id\":\"tTkbX7TdzMceKmCqW\",\"username\":\"arthur.giustina\"},\"_updatedAt\":\"2017-12-29T13:24:13.100Z\",\"jitsiTimeout\":\"2017-11-07T16:57:22.223Z\",\"customFields\":{},\"ro\":false},{\"_id\":\"GENERAL\",\"name\":\"general\",\"t\":\"c\",\"topic\":\"Community support in [#support](https://demo.rocket.chat/channel/support). Discussions in our [forums](https://forums.rocket.chat/). Find jobs in [#jobs](https://demo.rocket.chat/channel/jobs)\",\"announcement\":\"Try our new discussion forums - https://forums.rocket.chat\",\"muted\":[\"geekgonecrazy\"],\"_updatedAt\":\"2017-12-29T13:32:07.017Z\",\"jitsiTimeout\":\"2017-09-15T00:27:28.892Z\",\"default\":true}],\"remove\":[],\"success\":true}\n" -const val SUBSCRIPTIONS_OK = "{\"update\":[{\"t\":\"d\",\"ts\":\"2017-07-03T21:05:57.742Z\",\"ls\":\"2017-07-03T21:05:57.742Z\",\"name\":\"rocket.cat\",\"fname\":\"Rocket.Cat\",\"rid\":\"cBD6dHc7oBvGjkruMrocket.cat\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-20T10:52:55.624Z\",\"_id\":\"ETavwSdZEXMgDK2d6\"},{\"t\":\"d\",\"name\":\"andrey.k\",\"fname\":\"Andrey K\",\"rid\":\"cBD6dHc7oBvGjkruMnGgokxmGQtrwe4qyh\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-26T10:02:11.510Z\",\"_id\":\"G38YRCnvF5KJy7ZcW\"},{\"t\":\"d\",\"ls\":\"2017-07-19T00:58:55.048Z\",\"name\":\"kaikos\",\"fname\":\"أيت أورير 24\",\"rid\":\"cBD6dHc7oBvGjkruMkcqDE6baR7Y5gHLEf\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-12T17:05:44.148Z\",\"_id\":\"LMRohJAbxG7i3zko8\"},{\"t\":\"d\",\"ts\":\"2017-07-19T17:02:58.275Z\",\"ls\":\"2017-07-19T19:56:17.653Z\",\"name\":\"karan-96\",\"fname\":\"Karan Batra\",\"rid\":\"cBD6dHc7oBvGjkruMw4XQhPWoSCN29ZtQG\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-11-11T06:53:48.712Z\",\"_id\":\"MHNu4kMocapR9XYAJ\"},{\"t\":\"d\",\"ls\":\"2017-07-15T18:17:18.492Z\",\"name\":\"feliphe\",\"fname\":\"Feliphe Queiróz\",\"rid\":\"cBD6dHc7oBvGjkruMrdDGZc75Grpnd5Tdf\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-10-12T19:38:32.293Z\",\"_id\":\"PrLQYBDsHzPmJdunc\"},{\"t\":\"d\",\"ts\":\"2017-08-04T18:16:55.571Z\",\"ls\":\"2017-10-31T19:59:05.144Z\",\"name\":\"aaron.ogle\",\"fname\":\"Aaron Ogle\",\"rid\":\"7fw6XRQWHi4Ak3zj4cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T10:13:25.819Z\",\"_id\":\"RDMfebit3EGpgtXNA\"},{\"t\":\"d\",\"ts\":\"2017-06-23T12:30:44.291Z\",\"ls\":\"2017-12-22T13:06:44.491Z\",\"name\":\"rafael.kellermann\",\"fname\":\"Rafael Kellermann Streit\",\"rid\":\"MHNCPQyQnzdjRPiuRcBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T02:35:25.003Z\",\"_id\":\"aauhEcjXBcdEaJNSy\"},{\"t\":\"d\",\"ls\":\"2017-07-13T00:51:36.424Z\",\"name\":\"matheus.jardim.bernardes\",\"fname\":\"Matheus Jardim Bernardes\",\"rid\":\"cBD6dHc7oBvGjkruMnBe2T2HXC6KEyzK2P\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-10-19T16:10:21.664Z\",\"_id\":\"g7JaxybhyAGBqhBM5\"},{\"t\":\"d\",\"ts\":\"2017-08-18T22:27:49.246Z\",\"ls\":\"2017-08-18T22:27:49.246Z\",\"name\":\"FlavioTI\",\"fname\":\"Flávio Dagnoni (Geração android)\",\"rid\":\"G75tcPe8QHAL56BZ4cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"pK7gqY9YQxgjTYdHL\"},{\"t\":\"d\",\"ls\":\"2017-06-23T12:39:24.757Z\",\"name\":\"hubot\",\"fname\":\"Hubot\",\"rid\":\"YdpayxcMhWFGKRZb3cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-28T11:16:32.149Z\",\"_id\":\"pSrSkBpeSHhfdKmv3\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:04.636Z\",\"ls\":\"2017-08-01T13:28:38.159Z\",\"name\":\"android-dev-internal\",\"rid\":\"nNT3JREJNY8j7uFHX\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"archived\":true,\"_updatedAt\":\"2017-09-06T12:43:31.954Z\",\"_id\":\"9rmunswiCuak85Ahk\"},{\"t\":\"d\",\"ls\":\"2017-11-23T18:00:27.783Z\",\"name\":\"marcelo.schmidt\",\"fname\":\"Marcelo Schmidt\",\"rid\":\"cBD6dHc7oBvGjkruMjrnR99viqXELp4XYn\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T08:59:09.698Z\",\"_id\":\"seNSMZw7r644kkGun\"},{\"t\":\"d\",\"ls\":\"2017-10-02T19:26:48.285Z\",\"name\":\"sachin.shinde\",\"fname\":\"sachin shinde\",\"rid\":\"cBD6dHc7oBvGjkruMg9vNPgp6C4nDpSp8W\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T19:27:08.189Z\",\"_id\":\"NLn8dP3novYDkMz5N\"},{\"t\":\"d\",\"ts\":\"2017-08-04T17:40:40.040Z\",\"ls\":\"2017-08-04T17:40:40.040Z\",\"name\":\"1111111\",\"fname\":\"Andrew Axelrod\",\"rid\":\"cBD6dHc7oBvGjkruMkAuTB2QwESvC6XWtB\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"gYvYPReKPDq9taNvA\"},{\"t\":\"d\",\"ts\":\"2017-08-04T18:37:55.628Z\",\"ls\":\"2017-08-04T18:37:55.628Z\",\"name\":\"rafa\",\"fname\":\"Rafael\",\"rid\":\"cBD6dHc7oBvGjkruMoJWt2aGXP7wo9gPBi\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"jcoazmW5FsuTits9j\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:42.375Z\",\"ls\":\"2017-08-29T00:20:00.379Z\",\"name\":\"mobile-native\",\"rid\":\"N8HuZbMTSeZyZi6wc\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"archived\":true,\"_updatedAt\":\"2017-09-06T12:43:15.877Z\",\"_id\":\"a7k4pBX5J9Rjuy9jc\"},{\"t\":\"d\",\"ts\":\"2017-08-09T00:59:28.184Z\",\"ls\":\"2017-08-09T00:59:28.184Z\",\"name\":\"changwuf31\",\"fname\":\"Jhon Wang\",\"rid\":\"cBD6dHc7oBvGjkruMrXNAqsj2LJCCyqE6D\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"oJ68wTsiAEtbcmud4\"},{\"t\":\"d\",\"ts\":\"2017-08-16T17:12:40.722Z\",\"ls\":\"2017-08-28T18:41:05.288Z\",\"name\":\"karl.prieb\",\"fname\":\"Karl Prieb\",\"rid\":\"cBD6dHc7oBvGjkruMosnQaABmyfQoadYqW\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T20:52:04.317Z\",\"_id\":\"2wdBC8TnS273C8gpB\"},{\"t\":\"d\",\"ts\":\"2017-08-14T23:34:37.894Z\",\"ls\":\"2017-08-14T23:34:37.894Z\",\"name\":\"Arnab\",\"fname\":\"Md. Hasib Hasan Tarafder\",\"rid\":\"Cbmjf5XxJoSpQtd6EcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"LSEc34rxYiHTGvszm\"},{\"t\":\"d\",\"ts\":\"2017-08-22T16:29:19.776Z\",\"ls\":\"2017-10-06T21:10:07.953Z\",\"name\":\"filipedelimabrito\",\"fname\":\"filipedelimabrito\",\"rid\":\"8WCaFa2Jve4FNjMYacBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-04T20:31:10.980Z\",\"_id\":\"QXaNp96cRDhTCWs8N\"},{\"t\":\"d\",\"ls\":\"2017-12-06T00:24:11.198Z\",\"name\":\"leonardo.aramaki\",\"fname\":\"Leonardo Aramaki\",\"rid\":\"cBD6dHc7oBvGjkruMuWiyfQkgekhXywvKw\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T04:10:13.457Z\",\"_id\":\"xWrXyBQyz6BFfhnFz\"},{\"t\":\"d\",\"ts\":\"2017-08-17T11:11:10.669Z\",\"ls\":\"2017-08-17T11:11:10.669Z\",\"name\":\"Leossandro\",\"fname\":\"Leo Sandro\",\"rid\":\"YWPMv8Z33hdQ9h6NkcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"dKFpsJCmq976ne4jf\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:36.537Z\",\"ls\":\"2017-10-31T19:48:05.901Z\",\"name\":\"movile\",\"rid\":\"jyki6cZ338aisMsG9\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-31T19:48:05.901Z\",\"_id\":\"4aXuMTzK4Hq7YTPxA\"},{\"t\":\"d\",\"ts\":\"2017-08-18T22:29:22.230Z\",\"ls\":\"2017-08-18T22:29:22.230Z\",\"name\":\"Brandon.Toledano\",\"fname\":\"Brandon Toledano\",\"rid\":\"cBD6dHc7oBvGjkruMufcwE9NeH8MKik7AS\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-12T03:23:12.810Z\",\"_id\":\"eXPCC5pRuY6qQ68x8\"},{\"t\":\"d\",\"ls\":\"2017-09-18T13:03:07.636Z\",\"name\":\"julia.grala\",\"fname\":\"Júlia Grala Nogueira\",\"rid\":\"F6gZmaujtQceMst7TcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T17:55:29.461Z\",\"_id\":\"d2SRNTzK6td84dKoi\"},{\"t\":\"c\",\"ts\":\"2017-09-01T18:04:05.967Z\",\"ls\":\"2017-10-10T00:06:53.217Z\",\"name\":\"filipedelimabrito-public-channel\",\"fname\":\"filipedelimabrito-public-channel\",\"rid\":\"F3WPrkRCHsQXnkpQE\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-10T00:06:53.217Z\",\"_id\":\"X9wAysc2DZ3TYgxHi\"},{\"t\":\"p\",\"ts\":\"2017-09-12T13:47:08.630Z\",\"ls\":\"2017-12-04T13:22:05.941Z\",\"name\":\"mobile-circleci\",\"fname\":\"mobile-circleci\",\"rid\":\"Qhyt2tDnJ7H3ELMcC\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-04T13:22:05.941Z\",\"_id\":\"kDBNBBuhyQexSm7Ff\"},{\"t\":\"d\",\"ts\":\"2017-09-14T18:32:38.247Z\",\"ls\":\"2017-10-26T18:23:41.597Z\",\"name\":\"bradley.hilton\",\"fname\":\"Bradley Hilton\",\"rid\":\"KCEnsZw4GHwcXrRrEcBD6dHc7oBvGjkruM\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T04:58:05.263Z\",\"_id\":\"LraSDQfWEmAfFbRik\"},{\"t\":\"d\",\"ts\":\"2017-09-20T17:23:13.017Z\",\"ls\":\"2017-09-29T16:27:04.755Z\",\"name\":\"rodrigo.nascimento\",\"fname\":\"Rodrigo Nascimento\",\"rid\":\"MZiFvWAfF4RF4AD5ucBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T11:34:16.015Z\",\"_id\":\"9cWyfKvGiBQ6o2FLs\"},{\"t\":\"p\",\"ts\":\"2017-10-11T00:09:45.971Z\",\"ls\":\"2017-10-12T00:17:02.436Z\",\"name\":\"rocketchat-security\",\"fname\":\"rocketchat-security\",\"rid\":\"YFGDi4YmQEda4FkPC\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-12T00:17:02.436Z\",\"_id\":\"MxbhCnx79DCkp3auG\"},{\"t\":\"d\",\"ts\":\"2017-10-13T19:04:47.016Z\",\"ls\":\"2017-10-13T19:27:38.039Z\",\"name\":\"matheus.cardoso\",\"fname\":\"Matheus Cardoso\",\"rid\":\"cBD6dHc7oBvGjkruMj6Ge8FJTqjNyQoJsv\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T11:49:40.364Z\",\"_id\":\"xmgnPKxemvJqLBhEM\"},{\"t\":\"d\",\"ls\":\"2017-11-16T18:57:10.526Z\",\"name\":\"arthur.giustina\",\"fname\":\"Arthur Della Giustina\",\"rid\":\"cBD6dHc7oBvGjkruMtTkbX7TdzMceKmCqW\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T06:47:25.962Z\",\"_id\":\"dD7NMYHMeDmjrHoZu\"},{\"t\":\"p\",\"ts\":\"2017-11-08T17:06:08.550Z\",\"ls\":\"2017-12-21T20:51:42.592Z\",\"name\":\"officevibe\",\"fname\":\"officevibe\",\"rid\":\"Br5ZisLJ8va98jFBD\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-21T20:51:42.592Z\",\"_id\":\"PndGhg8c5JwLzkQRW\"},{\"t\":\"d\",\"ts\":\"2017-11-29T14:22:37.253Z\",\"ls\":\"2017-11-29T14:22:37.253Z\",\"name\":\"ramon.nobre\",\"fname\":\"Ramon\",\"rid\":\"3r7JSBtEGaeaPWjsicBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-17T20:38:07.529Z\",\"_id\":\"nupLzwrf8Cz2ywqoE\"},{\"t\":\"d\",\"name\":\"le0ssa\",\"fname\":\"le0ssa\",\"rid\":\"FaXMyHqbNJbPq6Ym9cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-26T22:12:42.802Z\",\"_id\":\"aNMJ7YBKK8cwhF3hd\"},{\"t\":\"p\",\"ts\":\"2017-12-21T19:48:11.499Z\",\"ls\":\"2017-12-22T09:44:58.972Z\",\"name\":\"rocket.chat.summit\",\"fname\":\"rocket.chat.summit\",\"rid\":\"2B6NWL88MoijfZswt\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-22T09:44:58.972Z\",\"_id\":\"Gv529Ake59Lpk56hr\"},{\"t\":\"c\",\"ts\":\"2017-06-23T13:45:59.935Z\",\"ls\":\"2017-12-28T13:20:05.819Z\",\"name\":\"androidnativeapp\",\"rid\":\"mSCEim3yGNb2rZhev\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T13:20:05.819Z\",\"_id\":\"h6F5evEdmXo8rwsoA\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:26.688Z\",\"ls\":\"2017-12-28T13:21:44.463Z\",\"name\":\"random\",\"rid\":\"k46YezYaE9jmvi7uM\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T13:21:44.463Z\",\"_id\":\"f9aobJRXcdwTEpmQf\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:08.110Z\",\"ls\":\"2017-12-28T17:24:18.085Z\",\"name\":\"android-native-sdk\",\"rid\":\"2vmeeZapHrxqWKif2\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:24:18.085Z\",\"_id\":\"wpfdt8yN7AgxXFBit\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:11.778Z\",\"ls\":\"2017-12-28T17:30:42.199Z\",\"name\":\"important\",\"rid\":\"QG6WKaB3YZKzv2ykN\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:30:42.199Z\",\"_id\":\"kudTrSy66TxWYTf7P\"},{\"t\":\"d\",\"ls\":\"2017-12-28T17:47:01.270Z\",\"name\":\"patricia.ferreira\",\"fname\":\"Patricia Ferreira\",\"rid\":\"KK6xPd6zQb5MyEjYbcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:47:01.270Z\",\"_id\":\"KChQdaKHHcssJRY9X\"},{\"t\":\"p\",\"ts\":\"2017-09-29T16:48:11.578Z\",\"ls\":\"2017-12-28T17:53:55.045Z\",\"name\":\"rocketchat-working-on\",\"fname\":\"rocketchat-working-on\",\"rid\":\"Y6587MM9T2ca4m9AP\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:53:55.045Z\",\"_id\":\"NwayWg3QYkgBtf6yR\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:49.910Z\",\"ls\":\"2017-12-28T18:00:22.964Z\",\"name\":\"rocket-dev\",\"rid\":\"FATCnDk5egNtRvQfv\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T18:00:22.964Z\",\"_id\":\"KQ7E5Wupm3zgwbuGn\"},{\"t\":\"p\",\"ts\":\"2017-08-15T13:55:45.678Z\",\"ls\":\"2017-12-28T18:00:32.714Z\",\"name\":\"android-app-rewrite\",\"fname\":\"android-app-rewrite\",\"rid\":\"5KAw6vTLBkSJKefae\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":null},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T18:00:32.714Z\",\"_id\":\"5RR63MR3gCpCjDwXL\"},{\"t\":\"d\",\"ls\":\"2017-12-28T23:51:18.324Z\",\"name\":\"lucio.maciel\",\"fname\":\"Lucio F. Maciel\",\"rid\":\"8MyxXwfqeioYwmnnKcBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T23:51:18.324Z\",\"_id\":\"N3wquauNbqcE2DjQf\"},{\"t\":\"c\",\"ts\":\"2017-12-28T17:32:21.630Z\",\"ls\":\"2017-12-29T12:59:12.003Z\",\"name\":\"jobs\",\"fname\":null,\"rid\":\"uaNMXwBvMSd8Lt2zG\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T12:59:12.003Z\",\"_id\":\"PMi8KzCM2cmKXHspk\"},{\"t\":\"c\",\"ts\":\"2017-09-21T19:01:58.358Z\",\"ls\":\"2017-12-29T12:59:38.759Z\",\"name\":\"iosnativeapp\",\"fname\":null,\"rid\":\"9fcPiSCwpW8uB6fok\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T12:59:38.759Z\",\"_id\":\"FfAp2WJckty6QMNXM\"},{\"t\":\"p\",\"ts\":\"2017-07-25T14:23:51.478Z\",\"ls\":\"2017-12-29T13:15:32.565Z\",\"name\":\"mobile-internal\",\"rid\":\"tn3EiAYecbtXGEBDn\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"archived\":false,\"_updatedAt\":\"2017-12-29T13:15:32.565Z\",\"_id\":\"f7whSKN8JXy9v8zYT\"},{\"t\":\"p\",\"ts\":\"2017-12-29T13:21:20.960Z\",\"ls\":\"2017-12-29T13:25:52.901Z\",\"name\":\"rocketchat-ux\",\"fname\":\"rocketchat-ux\",\"rid\":\"AALrfqnPPNykhvhWo\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T13:25:52.901Z\",\"_id\":\"PF8g9i7pKzZqBBZEm\"},{\"t\":\"c\",\"ts\":\"2017-06-23T12:30:03.592Z\",\"ls\":\"2017-12-29T13:35:47.991Z\",\"name\":\"general\",\"rid\":\"GENERAL\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T13:35:47.991Z\",\"disableNotifications\":true,\"hideUnreadStatus\":true,\"_id\":\"vbQdXYh5vjKXbRjBz\"}],\"remove\":[],\"success\":true}\n" +const val SUBSCRIPTIONS_OK = + "{\"update\":[{\"t\":\"d\",\"ts\":\"2017-07-03T21:05:57.742Z\",\"ls\":\"2017-07-03T21:05:57.742Z\",\"name\":\"rocket.cat\",\"fname\":\"Rocket.Cat\",\"rid\":\"cBD6dHc7oBvGjkruMrocket.cat\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-20T10:52:55.624Z\",\"_id\":\"ETavwSdZEXMgDK2d6\"},{\"t\":\"d\",\"name\":\"andrey.k\",\"fname\":\"Andrey K\",\"rid\":\"cBD6dHc7oBvGjkruMnGgokxmGQtrwe4qyh\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-26T10:02:11.510Z\",\"_id\":\"G38YRCnvF5KJy7ZcW\"},{\"t\":\"d\",\"ls\":\"2017-07-19T00:58:55.048Z\",\"name\":\"kaikos\",\"fname\":\"أيت أورير 24\",\"rid\":\"cBD6dHc7oBvGjkruMkcqDE6baR7Y5gHLEf\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-12T17:05:44.148Z\",\"_id\":\"LMRohJAbxG7i3zko8\"},{\"t\":\"d\",\"ts\":\"2017-07-19T17:02:58.275Z\",\"ls\":\"2017-07-19T19:56:17.653Z\",\"name\":\"karan-96\",\"fname\":\"Karan Batra\",\"rid\":\"cBD6dHc7oBvGjkruMw4XQhPWoSCN29ZtQG\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-11-11T06:53:48.712Z\",\"_id\":\"MHNu4kMocapR9XYAJ\"},{\"t\":\"d\",\"ls\":\"2017-07-15T18:17:18.492Z\",\"name\":\"feliphe\",\"fname\":\"Feliphe Queiróz\",\"rid\":\"cBD6dHc7oBvGjkruMrdDGZc75Grpnd5Tdf\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-10-12T19:38:32.293Z\",\"_id\":\"PrLQYBDsHzPmJdunc\"},{\"t\":\"d\",\"ts\":\"2017-08-04T18:16:55.571Z\",\"ls\":\"2017-10-31T19:59:05.144Z\",\"name\":\"aaron.ogle\",\"fname\":\"Aaron Ogle\",\"rid\":\"7fw6XRQWHi4Ak3zj4cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T10:13:25.819Z\",\"_id\":\"RDMfebit3EGpgtXNA\"},{\"t\":\"d\",\"ts\":\"2017-06-23T12:30:44.291Z\",\"ls\":\"2017-12-22T13:06:44.491Z\",\"name\":\"rafael.kellermann\",\"fname\":\"Rafael Kellermann Streit\",\"rid\":\"MHNCPQyQnzdjRPiuRcBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T02:35:25.003Z\",\"_id\":\"aauhEcjXBcdEaJNSy\"},{\"t\":\"d\",\"ls\":\"2017-07-13T00:51:36.424Z\",\"name\":\"matheus.jardim.bernardes\",\"fname\":\"Matheus Jardim Bernardes\",\"rid\":\"cBD6dHc7oBvGjkruMnBe2T2HXC6KEyzK2P\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-10-19T16:10:21.664Z\",\"_id\":\"g7JaxybhyAGBqhBM5\"},{\"t\":\"d\",\"ts\":\"2017-08-18T22:27:49.246Z\",\"ls\":\"2017-08-18T22:27:49.246Z\",\"name\":\"FlavioTI\",\"fname\":\"Flávio Dagnoni (Geração android)\",\"rid\":\"G75tcPe8QHAL56BZ4cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"pK7gqY9YQxgjTYdHL\"},{\"t\":\"d\",\"ls\":\"2017-06-23T12:39:24.757Z\",\"name\":\"hubot\",\"fname\":\"Hubot\",\"rid\":\"YdpayxcMhWFGKRZb3cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"_updatedAt\":\"2017-12-28T11:16:32.149Z\",\"_id\":\"pSrSkBpeSHhfdKmv3\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:04.636Z\",\"ls\":\"2017-08-01T13:28:38.159Z\",\"name\":\"android-dev-internal\",\"rid\":\"nNT3JREJNY8j7uFHX\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"archived\":true,\"_updatedAt\":\"2017-09-06T12:43:31.954Z\",\"_id\":\"9rmunswiCuak85Ahk\"},{\"t\":\"d\",\"ls\":\"2017-11-23T18:00:27.783Z\",\"name\":\"marcelo.schmidt\",\"fname\":\"Marcelo Schmidt\",\"rid\":\"cBD6dHc7oBvGjkruMjrnR99viqXELp4XYn\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T08:59:09.698Z\",\"_id\":\"seNSMZw7r644kkGun\"},{\"t\":\"d\",\"ls\":\"2017-10-02T19:26:48.285Z\",\"name\":\"sachin.shinde\",\"fname\":\"sachin shinde\",\"rid\":\"cBD6dHc7oBvGjkruMg9vNPgp6C4nDpSp8W\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T19:27:08.189Z\",\"_id\":\"NLn8dP3novYDkMz5N\"},{\"t\":\"d\",\"ts\":\"2017-08-04T17:40:40.040Z\",\"ls\":\"2017-08-04T17:40:40.040Z\",\"name\":\"1111111\",\"fname\":\"Andrew Axelrod\",\"rid\":\"cBD6dHc7oBvGjkruMkAuTB2QwESvC6XWtB\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"gYvYPReKPDq9taNvA\"},{\"t\":\"d\",\"ts\":\"2017-08-04T18:37:55.628Z\",\"ls\":\"2017-08-04T18:37:55.628Z\",\"name\":\"rafa\",\"fname\":\"Rafael\",\"rid\":\"cBD6dHc7oBvGjkruMoJWt2aGXP7wo9gPBi\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"jcoazmW5FsuTits9j\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:42.375Z\",\"ls\":\"2017-08-29T00:20:00.379Z\",\"name\":\"mobile-native\",\"rid\":\"N8HuZbMTSeZyZi6wc\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"archived\":true,\"_updatedAt\":\"2017-09-06T12:43:15.877Z\",\"_id\":\"a7k4pBX5J9Rjuy9jc\"},{\"t\":\"d\",\"ts\":\"2017-08-09T00:59:28.184Z\",\"ls\":\"2017-08-09T00:59:28.184Z\",\"name\":\"changwuf31\",\"fname\":\"Jhon Wang\",\"rid\":\"cBD6dHc7oBvGjkruMrXNAqsj2LJCCyqE6D\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"oJ68wTsiAEtbcmud4\"},{\"t\":\"d\",\"ts\":\"2017-08-16T17:12:40.722Z\",\"ls\":\"2017-08-28T18:41:05.288Z\",\"name\":\"karl.prieb\",\"fname\":\"Karl Prieb\",\"rid\":\"cBD6dHc7oBvGjkruMosnQaABmyfQoadYqW\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T20:52:04.317Z\",\"_id\":\"2wdBC8TnS273C8gpB\"},{\"t\":\"d\",\"ts\":\"2017-08-14T23:34:37.894Z\",\"ls\":\"2017-08-14T23:34:37.894Z\",\"name\":\"Arnab\",\"fname\":\"Md. Hasib Hasan Tarafder\",\"rid\":\"Cbmjf5XxJoSpQtd6EcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"LSEc34rxYiHTGvszm\"},{\"t\":\"d\",\"ts\":\"2017-08-22T16:29:19.776Z\",\"ls\":\"2017-10-06T21:10:07.953Z\",\"name\":\"filipedelimabrito\",\"fname\":\"filipedelimabrito\",\"rid\":\"8WCaFa2Jve4FNjMYacBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-04T20:31:10.980Z\",\"_id\":\"QXaNp96cRDhTCWs8N\"},{\"t\":\"d\",\"ls\":\"2017-12-06T00:24:11.198Z\",\"name\":\"leonardo.aramaki\",\"fname\":\"Leonardo Aramaki\",\"rid\":\"cBD6dHc7oBvGjkruMuWiyfQkgekhXywvKw\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T04:10:13.457Z\",\"_id\":\"xWrXyBQyz6BFfhnFz\"},{\"t\":\"d\",\"ts\":\"2017-08-17T11:11:10.669Z\",\"ls\":\"2017-08-17T11:11:10.669Z\",\"name\":\"Leossandro\",\"fname\":\"Leo Sandro\",\"rid\":\"YWPMv8Z33hdQ9h6NkcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-08-22T18:20:12.159Z\",\"_id\":\"dKFpsJCmq976ne4jf\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:36.537Z\",\"ls\":\"2017-10-31T19:48:05.901Z\",\"name\":\"movile\",\"rid\":\"jyki6cZ338aisMsG9\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-31T19:48:05.901Z\",\"_id\":\"4aXuMTzK4Hq7YTPxA\"},{\"t\":\"d\",\"ts\":\"2017-08-18T22:29:22.230Z\",\"ls\":\"2017-08-18T22:29:22.230Z\",\"name\":\"Brandon.Toledano\",\"fname\":\"Brandon Toledano\",\"rid\":\"cBD6dHc7oBvGjkruMufcwE9NeH8MKik7AS\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-12T03:23:12.810Z\",\"_id\":\"eXPCC5pRuY6qQ68x8\"},{\"t\":\"d\",\"ls\":\"2017-09-18T13:03:07.636Z\",\"name\":\"julia.grala\",\"fname\":\"Júlia Grala Nogueira\",\"rid\":\"F6gZmaujtQceMst7TcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-27T17:55:29.461Z\",\"_id\":\"d2SRNTzK6td84dKoi\"},{\"t\":\"c\",\"ts\":\"2017-09-01T18:04:05.967Z\",\"ls\":\"2017-10-10T00:06:53.217Z\",\"name\":\"filipedelimabrito-public-channel\",\"fname\":\"filipedelimabrito-public-channel\",\"rid\":\"F3WPrkRCHsQXnkpQE\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-10T00:06:53.217Z\",\"_id\":\"X9wAysc2DZ3TYgxHi\"},{\"t\":\"p\",\"ts\":\"2017-09-12T13:47:08.630Z\",\"ls\":\"2017-12-04T13:22:05.941Z\",\"name\":\"mobile-circleci\",\"fname\":\"mobile-circleci\",\"rid\":\"Qhyt2tDnJ7H3ELMcC\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-04T13:22:05.941Z\",\"_id\":\"kDBNBBuhyQexSm7Ff\"},{\"t\":\"d\",\"ts\":\"2017-09-14T18:32:38.247Z\",\"ls\":\"2017-10-26T18:23:41.597Z\",\"name\":\"bradley.hilton\",\"fname\":\"Bradley Hilton\",\"rid\":\"KCEnsZw4GHwcXrRrEcBD6dHc7oBvGjkruM\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T04:58:05.263Z\",\"_id\":\"LraSDQfWEmAfFbRik\"},{\"t\":\"d\",\"ts\":\"2017-09-20T17:23:13.017Z\",\"ls\":\"2017-09-29T16:27:04.755Z\",\"name\":\"rodrigo.nascimento\",\"fname\":\"Rodrigo Nascimento\",\"rid\":\"MZiFvWAfF4RF4AD5ucBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T11:34:16.015Z\",\"_id\":\"9cWyfKvGiBQ6o2FLs\"},{\"t\":\"p\",\"ts\":\"2017-10-11T00:09:45.971Z\",\"ls\":\"2017-10-12T00:17:02.436Z\",\"name\":\"rocketchat-security\",\"fname\":\"rocketchat-security\",\"rid\":\"YFGDi4YmQEda4FkPC\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-10-12T00:17:02.436Z\",\"_id\":\"MxbhCnx79DCkp3auG\"},{\"t\":\"d\",\"ts\":\"2017-10-13T19:04:47.016Z\",\"ls\":\"2017-10-13T19:27:38.039Z\",\"name\":\"matheus.cardoso\",\"fname\":\"Matheus Cardoso\",\"rid\":\"cBD6dHc7oBvGjkruMj6Ge8FJTqjNyQoJsv\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T11:49:40.364Z\",\"_id\":\"xmgnPKxemvJqLBhEM\"},{\"t\":\"d\",\"ls\":\"2017-11-16T18:57:10.526Z\",\"name\":\"arthur.giustina\",\"fname\":\"Arthur Della Giustina\",\"rid\":\"cBD6dHc7oBvGjkruMtTkbX7TdzMceKmCqW\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T06:47:25.962Z\",\"_id\":\"dD7NMYHMeDmjrHoZu\"},{\"t\":\"p\",\"ts\":\"2017-11-08T17:06:08.550Z\",\"ls\":\"2017-12-21T20:51:42.592Z\",\"name\":\"officevibe\",\"fname\":\"officevibe\",\"rid\":\"Br5ZisLJ8va98jFBD\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-21T20:51:42.592Z\",\"_id\":\"PndGhg8c5JwLzkQRW\"},{\"t\":\"d\",\"ts\":\"2017-11-29T14:22:37.253Z\",\"ls\":\"2017-11-29T14:22:37.253Z\",\"name\":\"ramon.nobre\",\"fname\":\"Ramon\",\"rid\":\"3r7JSBtEGaeaPWjsicBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-17T20:38:07.529Z\",\"_id\":\"nupLzwrf8Cz2ywqoE\"},{\"t\":\"d\",\"name\":\"le0ssa\",\"fname\":\"le0ssa\",\"rid\":\"FaXMyHqbNJbPq6Ym9cBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":false,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-26T22:12:42.802Z\",\"_id\":\"aNMJ7YBKK8cwhF3hd\"},{\"t\":\"p\",\"ts\":\"2017-12-21T19:48:11.499Z\",\"ls\":\"2017-12-22T09:44:58.972Z\",\"name\":\"rocket.chat.summit\",\"fname\":\"rocket.chat.summit\",\"rid\":\"2B6NWL88MoijfZswt\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-22T09:44:58.972Z\",\"_id\":\"Gv529Ake59Lpk56hr\"},{\"t\":\"c\",\"ts\":\"2017-06-23T13:45:59.935Z\",\"ls\":\"2017-12-28T13:20:05.819Z\",\"name\":\"androidnativeapp\",\"rid\":\"mSCEim3yGNb2rZhev\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T13:20:05.819Z\",\"_id\":\"h6F5evEdmXo8rwsoA\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:26.688Z\",\"ls\":\"2017-12-28T13:21:44.463Z\",\"name\":\"random\",\"rid\":\"k46YezYaE9jmvi7uM\",\"f\":false,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T13:21:44.463Z\",\"_id\":\"f9aobJRXcdwTEpmQf\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:08.110Z\",\"ls\":\"2017-12-28T17:24:18.085Z\",\"name\":\"android-native-sdk\",\"rid\":\"2vmeeZapHrxqWKif2\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:24:18.085Z\",\"_id\":\"wpfdt8yN7AgxXFBit\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:11.778Z\",\"ls\":\"2017-12-28T17:30:42.199Z\",\"name\":\"important\",\"rid\":\"QG6WKaB3YZKzv2ykN\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:30:42.199Z\",\"_id\":\"kudTrSy66TxWYTf7P\"},{\"t\":\"d\",\"ls\":\"2017-12-28T17:47:01.270Z\",\"name\":\"patricia.ferreira\",\"fname\":\"Patricia Ferreira\",\"rid\":\"KK6xPd6zQb5MyEjYbcBD6dHc7oBvGjkruM\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:47:01.270Z\",\"_id\":\"KChQdaKHHcssJRY9X\"},{\"t\":\"p\",\"ts\":\"2017-09-29T16:48:11.578Z\",\"ls\":\"2017-12-28T17:53:55.045Z\",\"name\":\"rocketchat-working-on\",\"fname\":\"rocketchat-working-on\",\"rid\":\"Y6587MM9T2ca4m9AP\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T17:53:55.045Z\",\"_id\":\"NwayWg3QYkgBtf6yR\"},{\"t\":\"p\",\"ts\":\"2017-06-23T13:46:49.910Z\",\"ls\":\"2017-12-28T18:00:22.964Z\",\"name\":\"rocket-dev\",\"rid\":\"FATCnDk5egNtRvQfv\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T18:00:22.964Z\",\"_id\":\"KQ7E5Wupm3zgwbuGn\"},{\"t\":\"p\",\"ts\":\"2017-08-15T13:55:45.678Z\",\"ls\":\"2017-12-28T18:00:32.714Z\",\"name\":\"android-app-rewrite\",\"fname\":\"android-app-rewrite\",\"rid\":\"5KAw6vTLBkSJKefae\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":null},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T18:00:32.714Z\",\"_id\":\"5RR63MR3gCpCjDwXL\"},{\"t\":\"d\",\"ls\":\"2017-12-28T23:51:18.324Z\",\"name\":\"lucio.maciel\",\"fname\":\"Lucio F. Maciel\",\"rid\":\"8MyxXwfqeioYwmnnKcBD6dHc7oBvGjkruM\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-28T23:51:18.324Z\",\"_id\":\"N3wquauNbqcE2DjQf\"},{\"t\":\"c\",\"ts\":\"2017-12-28T17:32:21.630Z\",\"ls\":\"2017-12-29T12:59:12.003Z\",\"name\":\"jobs\",\"fname\":null,\"rid\":\"uaNMXwBvMSd8Lt2zG\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T12:59:12.003Z\",\"_id\":\"PMi8KzCM2cmKXHspk\"},{\"t\":\"c\",\"ts\":\"2017-09-21T19:01:58.358Z\",\"ls\":\"2017-12-29T12:59:38.759Z\",\"name\":\"iosnativeapp\",\"fname\":null,\"rid\":\"9fcPiSCwpW8uB6fok\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T12:59:38.759Z\",\"_id\":\"FfAp2WJckty6QMNXM\"},{\"t\":\"p\",\"ts\":\"2017-07-25T14:23:51.478Z\",\"ls\":\"2017-12-29T13:15:32.565Z\",\"name\":\"mobile-internal\",\"rid\":\"tn3EiAYecbtXGEBDn\",\"f\":true,\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"archived\":false,\"_updatedAt\":\"2017-12-29T13:15:32.565Z\",\"_id\":\"f7whSKN8JXy9v8zYT\"},{\"t\":\"p\",\"ts\":\"2017-12-29T13:21:20.960Z\",\"ls\":\"2017-12-29T13:25:52.901Z\",\"name\":\"rocketchat-ux\",\"fname\":\"rocketchat-ux\",\"rid\":\"AALrfqnPPNykhvhWo\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\",\"name\":\"Filipe Brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T13:25:52.901Z\",\"_id\":\"PF8g9i7pKzZqBBZEm\"},{\"t\":\"c\",\"ts\":\"2017-06-23T12:30:03.592Z\",\"ls\":\"2017-12-29T13:35:47.991Z\",\"name\":\"general\",\"rid\":\"GENERAL\",\"u\":{\"_id\":\"cBD6dHc7oBvGjkruM\",\"username\":\"filipe.brito\"},\"open\":true,\"alert\":false,\"unread\":0,\"userMentions\":0,\"groupMentions\":0,\"_updatedAt\":\"2017-12-29T13:35:47.991Z\",\"disableNotifications\":true,\"hideUnreadStatus\":true,\"_id\":\"vbQdXYh5vjKXbRjBz\"}],\"remove\":[],\"success\":true}\n" const val SPOTLIGHT_OK = """ { @@ -167,13 +177,16 @@ const val SPOTLIGHT_OK = """ } """ -const val QUERY_USERS_SUCCESS = "{\"users\":[{\"_id\":\"2XjnFaM4unjqRh96A\",\"status\":\"offline\",\"name\":\"gbr\",\"username\":\"gbr\",\"active\":true,\"utcOffset\":-2,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22ekPacQhzNDTsjdh\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Guillaume Bourdages\"},{\"_id\":\"22Gi3Ly4vicbvgCgb\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Hieu Hiep Nguyen\",\"utcOffset\":7,\"username\":\"hieu.hiep.nguyen\"},{\"_id\":\"22M8zeDBQYswLNNq5\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Reginaldo Santos\",\"utcOffset\":-2,\"username\":\"reginaldosantos.br\"},{\"_id\":\"22nxm44GD9TDupPMd\",\"status\":\"offline\",\"active\":true,\"name\":\"irishnugget\",\"utcOffset\":-5,\"username\":\"irishnugget\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22ytF4wzso6srWbsQ\",\"status\":\"offline\",\"name\":\"Greg\",\"username\":\"ssorizdabest\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22zBQWatMzn47czgg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Gorge\",\"utcOffset\":-5,\"username\":\"gorge-1\"},{\"_id\":\"23478PFrdDxLFpYL4\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"khejing\",\"utcOffset\":8,\"username\":\"khejing\"},{\"_id\":\"235seAv3Po9uYv3PL\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Raffe Bergwall\",\"utcOffset\":2,\"username\":\"raffe.bergwall\"},{\"_id\":\"23YSKn8oZkdWg2XE3\",\"status\":\"offline\",\"name\":\"yangada\",\"username\":\"yangada\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"23w3J4eD2iSpLFbB7\",\"status\":\"offline\",\"active\":true,\"name\":\"Julian Lugod\",\"utcOffset\":8,\"username\":\"akiraaisha\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"23wN6zqD3CamJBYSy\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"dumingqiao\",\"utcOffset\":8,\"username\":\"dumingqiao\"},{\"_id\":\"244YgWgXCpKWF5HsK\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"algenerale\",\"utcOffset\":1,\"username\":\"algenerale\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"247ffn8NF75rrnWBv\",\"status\":\"offline\",\"name\":\"Alexandr Estegneev\",\"username\":\"estadok\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"247uRyvemCv87Xery\",\"status\":\"offline\",\"active\":true,\"name\":\"jav grvia\",\"utcOffset\":-5,\"username\":\"jav.grvia\",\"settings\":{\"preferences\":{\"useEmojis\":true,\"convertAsciiEmoji\":true,\"saveMobileBandwidth\":true,\"autoImageLoad\":true,\"viewMode\":0}},\"type\":\"user\"},{\"_id\":\"249cS934B56Nq45tH\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Serge Rodin\",\"utcOffset\":3,\"username\":\"serge.rodin\"},{\"_id\":\"24XdGFBmpgdXsC7ib\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"keeg\",\"utcOffset\":-5,\"username\":\"keeg\"},{\"_id\":\"24f4axXB7fDfvvntC\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"abcdefg\",\"utcOffset\":-7,\"username\":\"abcdefg-1\"},{\"_id\":\"24pupyrkX6nC4Qfsm\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Oleg Seregin\",\"utcOffset\":3,\"username\":\"Nartalon\"},{\"_id\":\"24rSi7zg3n9PErPtj\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Berislav Purgar\",\"utcOffset\":1,\"username\":\"joe.doe\"},{\"_id\":\"24trN3on8LvhEjYwT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Miguel Mendez\",\"utcOffset\":-5,\"username\":\"mikemndz\"},{\"_id\":\"24vSocp5xzSJ8CdHn\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Mung Thai\",\"utcOffset\":-4,\"username\":\"Mung.Thai\"},{\"_id\":\"2548PFDZ3Sbu7stpW\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Jason Jang\",\"utcOffset\":9,\"username\":\"jason.jang\"},{\"_id\":\"25kfvQZh5TZhZmkax\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Apta Gemilang\",\"utcOffset\":7,\"username\":\"sad231\"},{\"_id\":\"25oKJyvdMMMupbci9\",\"status\":\"offline\",\"name\":\"shige imo\",\"username\":\"shige.imo\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"25smgS9qBk6AumwRs\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"sasgroupeaxone\",\"utcOffset\":2,\"username\":\"sasgroupeaxone\"},{\"_id\":\"25tYKuxouEq8Y2PMr\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"yu zhang\",\"utcOffset\":8,\"username\":\"yu.zhang\"},{\"_id\":\"25woScsha2ZPamcGY\",\"status\":\"offline\",\"active\":true,\"name\":\"Hugo Henry\",\"utcOffset\":2,\"username\":\"hugo.henry\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"25yPxjaobvW4HjT2c\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"gregory\"},{\"_id\":\"25zkCHMLu32mr4XSA\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"changingedu@163.com\",\"utcOffset\":8,\"username\":\"changingeduat163.com\"},{\"_id\":\"26FvTvd2cQ4A4kEv5\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Magzhan Mekebai\",\"utcOffset\":6,\"username\":\"magzhan.mekebai\"},{\"_id\":\"26HazKt7ad9589R2o\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Sagar\",\"utcOffset\":-7,\"username\":\"sagar-3\"},{\"_id\":\"26Kgt5TtaqpNKctXT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"George Orwa\",\"utcOffset\":3,\"username\":\"george.orwa\"},{\"_id\":\"26ZtLhe6WTaPSenGJ\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Junseong Lee\",\"utcOffset\":9,\"username\":\"junseong.lee\"},{\"_id\":\"26fxNBhosPjQXuQa8\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Mario Behling\",\"utcOffset\":2,\"username\":\"mario.behling\"},{\"_id\":\"26muqz6kT8jscsHgL\",\"status\":\"offline\",\"active\":true,\"name\":\"Trygve Høiseth\",\"utcOffset\":1,\"username\":\"trygve.gaysir\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"26p4pn4QneRjNqSEg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Karlyn Fielding\",\"utcOffset\":-7,\"username\":\"karlyn.fielding\"},{\"_id\":\"26sLQXcYYEhMYpMk5\",\"status\":\"offline\",\"active\":true,\"name\":\"jgmiao\",\"utcOffset\":8,\"username\":\"jgmiao\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"26vQRwCJ4gvS9txBe\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Kwangyo Cho\",\"utcOffset\":9,\"username\":\"kwangyo.cho\"},{\"_id\":\"274axySChdZB7XDcg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"yuezang\",\"utcOffset\":8,\"username\":\"yuezang\"},{\"_id\":\"277wDtqrkWu5RRuiZ\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Monzerghasan\",\"utcOffset\":2,\"username\":\"monzerghasan\"},{\"_id\":\"27BbwSmFYNvoBEzBg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Thitipong Nick Krungkaew\",\"utcOffset\":7,\"username\":\"tuahear\"},{\"_id\":\"27dJfcEKiLjwaWC6X\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Andrew Huggins\",\"utcOffset\":-5,\"username\":\"ahuggins\"},{\"_id\":\"27tM4bLEDKuaYAfhm\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"George Rome\",\"utcOffset\":0,\"username\":\"george.rome\"},{\"_id\":\"27xj647aJ5QZvStLz\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Yongjiasu\",\"utcOffset\":8,\"username\":\"Yongjiasu\"},{\"_id\":\"2838d8SzccRjTspoT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Kim Banga\",\"utcOffset\":2,\"username\":\"kimbanga\"},{\"_id\":\"28G6ri5ib2kTv4Y5g\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Agon Bina\",\"utcOffset\":2,\"username\":\"abina\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28PZ9sjbmrzk5Mebb\",\"status\":\"offline\",\"name\":\"twegener\",\"username\":\"twegener\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28cNgahrcwm7wYCrg\",\"status\":\"offline\",\"active\":true,\"name\":\"Michael Taggart\",\"utcOffset\":-8,\"username\":\"mttaggart\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28i3sRrt95JMrKNRi\",\"status\":\"offline\",\"active\":true,\"name\":\"Anar-Erdene Batjargal\",\"utcOffset\":9,\"username\":\"anar.erdene.batjargal\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}}],\"count\":50,\"offset\":0,\"total\":28148,\"success\":true}" +const val QUERY_USERS_SUCCESS = + "{\"users\":[{\"_id\":\"2XjnFaM4unjqRh96A\",\"status\":\"offline\",\"name\":\"gbr\",\"username\":\"gbr\",\"active\":true,\"utcOffset\":-2,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22ekPacQhzNDTsjdh\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Guillaume Bourdages\"},{\"_id\":\"22Gi3Ly4vicbvgCgb\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Hieu Hiep Nguyen\",\"utcOffset\":7,\"username\":\"hieu.hiep.nguyen\"},{\"_id\":\"22M8zeDBQYswLNNq5\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Reginaldo Santos\",\"utcOffset\":-2,\"username\":\"reginaldosantos.br\"},{\"_id\":\"22nxm44GD9TDupPMd\",\"status\":\"offline\",\"active\":true,\"name\":\"irishnugget\",\"utcOffset\":-5,\"username\":\"irishnugget\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22ytF4wzso6srWbsQ\",\"status\":\"offline\",\"name\":\"Greg\",\"username\":\"ssorizdabest\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"22zBQWatMzn47czgg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Gorge\",\"utcOffset\":-5,\"username\":\"gorge-1\"},{\"_id\":\"23478PFrdDxLFpYL4\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"khejing\",\"utcOffset\":8,\"username\":\"khejing\"},{\"_id\":\"235seAv3Po9uYv3PL\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Raffe Bergwall\",\"utcOffset\":2,\"username\":\"raffe.bergwall\"},{\"_id\":\"23YSKn8oZkdWg2XE3\",\"status\":\"offline\",\"name\":\"yangada\",\"username\":\"yangada\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"23w3J4eD2iSpLFbB7\",\"status\":\"offline\",\"active\":true,\"name\":\"Julian Lugod\",\"utcOffset\":8,\"username\":\"akiraaisha\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"23wN6zqD3CamJBYSy\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"dumingqiao\",\"utcOffset\":8,\"username\":\"dumingqiao\"},{\"_id\":\"244YgWgXCpKWF5HsK\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"algenerale\",\"utcOffset\":1,\"username\":\"algenerale\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"247ffn8NF75rrnWBv\",\"status\":\"offline\",\"name\":\"Alexandr Estegneev\",\"username\":\"estadok\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"247uRyvemCv87Xery\",\"status\":\"offline\",\"active\":true,\"name\":\"jav grvia\",\"utcOffset\":-5,\"username\":\"jav.grvia\",\"settings\":{\"preferences\":{\"useEmojis\":true,\"convertAsciiEmoji\":true,\"saveMobileBandwidth\":true,\"autoImageLoad\":true,\"viewMode\":0}},\"type\":\"user\"},{\"_id\":\"249cS934B56Nq45tH\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Serge Rodin\",\"utcOffset\":3,\"username\":\"serge.rodin\"},{\"_id\":\"24XdGFBmpgdXsC7ib\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"keeg\",\"utcOffset\":-5,\"username\":\"keeg\"},{\"_id\":\"24f4axXB7fDfvvntC\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"abcdefg\",\"utcOffset\":-7,\"username\":\"abcdefg-1\"},{\"_id\":\"24pupyrkX6nC4Qfsm\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Oleg Seregin\",\"utcOffset\":3,\"username\":\"Nartalon\"},{\"_id\":\"24rSi7zg3n9PErPtj\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Berislav Purgar\",\"utcOffset\":1,\"username\":\"joe.doe\"},{\"_id\":\"24trN3on8LvhEjYwT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Miguel Mendez\",\"utcOffset\":-5,\"username\":\"mikemndz\"},{\"_id\":\"24vSocp5xzSJ8CdHn\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Mung Thai\",\"utcOffset\":-4,\"username\":\"Mung.Thai\"},{\"_id\":\"2548PFDZ3Sbu7stpW\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Jason Jang\",\"utcOffset\":9,\"username\":\"jason.jang\"},{\"_id\":\"25kfvQZh5TZhZmkax\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Apta Gemilang\",\"utcOffset\":7,\"username\":\"sad231\"},{\"_id\":\"25oKJyvdMMMupbci9\",\"status\":\"offline\",\"name\":\"shige imo\",\"username\":\"shige.imo\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"25smgS9qBk6AumwRs\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"sasgroupeaxone\",\"utcOffset\":2,\"username\":\"sasgroupeaxone\"},{\"_id\":\"25tYKuxouEq8Y2PMr\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"yu zhang\",\"utcOffset\":8,\"username\":\"yu.zhang\"},{\"_id\":\"25woScsha2ZPamcGY\",\"status\":\"offline\",\"active\":true,\"name\":\"Hugo Henry\",\"utcOffset\":2,\"username\":\"hugo.henry\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"25yPxjaobvW4HjT2c\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"gregory\"},{\"_id\":\"25zkCHMLu32mr4XSA\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"changingedu@163.com\",\"utcOffset\":8,\"username\":\"changingeduat163.com\"},{\"_id\":\"26FvTvd2cQ4A4kEv5\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Magzhan Mekebai\",\"utcOffset\":6,\"username\":\"magzhan.mekebai\"},{\"_id\":\"26HazKt7ad9589R2o\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Sagar\",\"utcOffset\":-7,\"username\":\"sagar-3\"},{\"_id\":\"26Kgt5TtaqpNKctXT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"George Orwa\",\"utcOffset\":3,\"username\":\"george.orwa\"},{\"_id\":\"26ZtLhe6WTaPSenGJ\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Junseong Lee\",\"utcOffset\":9,\"username\":\"junseong.lee\"},{\"_id\":\"26fxNBhosPjQXuQa8\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Mario Behling\",\"utcOffset\":2,\"username\":\"mario.behling\"},{\"_id\":\"26muqz6kT8jscsHgL\",\"status\":\"offline\",\"active\":true,\"name\":\"Trygve Høiseth\",\"utcOffset\":1,\"username\":\"trygve.gaysir\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"26p4pn4QneRjNqSEg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Karlyn Fielding\",\"utcOffset\":-7,\"username\":\"karlyn.fielding\"},{\"_id\":\"26sLQXcYYEhMYpMk5\",\"status\":\"offline\",\"active\":true,\"name\":\"jgmiao\",\"utcOffset\":8,\"username\":\"jgmiao\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"26vQRwCJ4gvS9txBe\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Kwangyo Cho\",\"utcOffset\":9,\"username\":\"kwangyo.cho\"},{\"_id\":\"274axySChdZB7XDcg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"yuezang\",\"utcOffset\":8,\"username\":\"yuezang\"},{\"_id\":\"277wDtqrkWu5RRuiZ\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Monzerghasan\",\"utcOffset\":2,\"username\":\"monzerghasan\"},{\"_id\":\"27BbwSmFYNvoBEzBg\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Thitipong Nick Krungkaew\",\"utcOffset\":7,\"username\":\"tuahear\"},{\"_id\":\"27dJfcEKiLjwaWC6X\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Andrew Huggins\",\"utcOffset\":-5,\"username\":\"ahuggins\"},{\"_id\":\"27tM4bLEDKuaYAfhm\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"George Rome\",\"utcOffset\":0,\"username\":\"george.rome\"},{\"_id\":\"27xj647aJ5QZvStLz\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Yongjiasu\",\"utcOffset\":8,\"username\":\"Yongjiasu\"},{\"_id\":\"2838d8SzccRjTspoT\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Kim Banga\",\"utcOffset\":2,\"username\":\"kimbanga\"},{\"_id\":\"28G6ri5ib2kTv4Y5g\",\"type\":\"user\",\"status\":\"offline\",\"active\":true,\"name\":\"Agon Bina\",\"utcOffset\":2,\"username\":\"abina\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28PZ9sjbmrzk5Mebb\",\"status\":\"offline\",\"name\":\"twegener\",\"username\":\"twegener\",\"active\":true,\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28cNgahrcwm7wYCrg\",\"status\":\"offline\",\"active\":true,\"name\":\"Michael Taggart\",\"utcOffset\":-8,\"username\":\"mttaggart\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}},{\"_id\":\"28i3sRrt95JMrKNRi\",\"status\":\"offline\",\"active\":true,\"name\":\"Anar-Erdene Batjargal\",\"utcOffset\":9,\"username\":\"anar.erdene.batjargal\",\"type\":\"user\",\"settings\":{\"preferences\":{\"viewMode\":0}}}],\"count\":50,\"offset\":0,\"total\":28148,\"success\":true}" const val INCORRECT_PARAM_PROVIDED = "{\"success\":false,\"error\":\"fun is not a function\"}" -const val CREATE_CHANNEL_SUCCESS = "{\"channel\":{\"_id\":\"JeJcd4PE9d9fvjakf\",\"name\":\"elf\",\"fname\":\"elf\",\"t\":\"c\",\"msgs\":0,\"u\":{\"_id\":\"MaBK2dquY8TbaH6d3\",\"username\":\"aniket03\"},\"customFields\":{},\"ts\":\"2018-03-13T14:42:46.849Z\",\"ro\":false,\"sysMes\":true,\"_updatedAt\":\"2018-03-13T14:42:46.850Z\"},\"success\":true}" +const val CREATE_CHANNEL_SUCCESS = + "{\"channel\":{\"_id\":\"JeJcd4PE9d9fvjakf\",\"name\":\"elf\",\"fname\":\"elf\",\"t\":\"c\",\"msgs\":0,\"u\":{\"_id\":\"MaBK2dquY8TbaH6d3\",\"username\":\"aniket03\"},\"customFields\":{},\"ts\":\"2018-03-13T14:42:46.849Z\",\"ro\":false,\"sysMes\":true,\"_updatedAt\":\"2018-03-13T14:42:46.850Z\"},\"success\":true}" -const val FAIL_DUPLICATE_CHANNEL = "{\"success\":false,\"error\":\"A channel with name 'elf' exists [error-duplicate-channel-name]\",\"errorType\":\"error-duplicate-channel-name\"}" +const val FAIL_DUPLICATE_CHANNEL = + "{\"success\":false,\"error\":\"A channel with name 'elf' exists [error-duplicate-channel-name]\",\"errorType\":\"error-duplicate-channel-name\"}" const val ROLES_OK = """ { @@ -185,7 +198,7 @@ const val ROLES_OK = """ "success": true } """ -//{"message":{"_id":"1abbbf94-c839-4436-9476-6de03011c1e0","rid":"GS3Ceh7BLJGzfto78","msg":"Não"}} +// {"message":{"_id":"1abbbf94-c839-4436-9476-6de03011c1e0","rid":"GS3Ceh7BLJGzfto78","msg":"Não"}} const val SEND_MESSAGE_WITH_ID_OK = """ { "message": { diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/CustomEmojiTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/CustomEmojiTest.kt index 24389fcf..9cf7567d 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/CustomEmojiTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/CustomEmojiTest.kt @@ -5,7 +5,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.MatcherAssert.assertThat import org.junit.Before diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/LoginTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/LoginTest.kt index 106ccdab..edd926bc 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/LoginTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/LoginTest.kt @@ -12,7 +12,7 @@ import com.nhaarman.mockito_kotlin.check import com.nhaarman.mockito_kotlin.verify import com.squareup.moshi.JsonEncodingException import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.CoreMatchers.instanceOf import org.hamcrest.MatcherAssert.assertThat diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/LogoutTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/LogoutTest.kt index 17de9b29..cf8d5c93 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/LogoutTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/LogoutTest.kt @@ -6,7 +6,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.CoreMatchers.instanceOf import org.hamcrest.MatcherAssert.assertThat diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/MessagesTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/MessagesTest.kt index f3871d27..9c505ad9 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/MessagesTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/MessagesTest.kt @@ -6,7 +6,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.MatcherAssert.assertThat import org.junit.After diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/PermissionsTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/PermissionsTest.kt index 6c15d86c..ee06563d 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/PermissionsTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/PermissionsTest.kt @@ -5,7 +5,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.MatcherAssert.assertThat import org.junit.After diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/RolesTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/RolesTest.kt index b417dc69..0f8e4477 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/RolesTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/RolesTest.kt @@ -6,7 +6,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.MatcherAssert.assertThat import org.junit.Before diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/SpotlightTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/SpotlightTest.kt index ec7c21c7..47b7be15 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/SpotlightTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/SpotlightTest.kt @@ -6,7 +6,7 @@ import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import chat.rocket.core.model.SpotlightResult import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.CoreMatchers.isA import org.hamcrest.MatcherAssert.assertThat diff --git a/core/src/test/kotlin/chat/rocket/core/internal/rest/UserTest.kt b/core/src/test/kotlin/chat/rocket/core/internal/rest/UserTest.kt index 36951b53..0199f544 100644 --- a/core/src/test/kotlin/chat/rocket/core/internal/rest/UserTest.kt +++ b/core/src/test/kotlin/chat/rocket/core/internal/rest/UserTest.kt @@ -9,7 +9,7 @@ import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository import io.fabric8.mockwebserver.DefaultMockServer -import kotlinx.coroutines.experimental.runBlocking +import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.instanceOf @@ -107,7 +107,7 @@ class UserTest { // } @Test - fun `updateProfile() should succeed with valid parameters` () { + fun `updateProfile() should succeed with valid parameters`() { mockServer.expect() .post() .withPath("/api/v1/users.update") @@ -151,7 +151,7 @@ class UserTest { runBlocking { try { - sut.updateProfile("userId", "test@email.com", null, null, "testuser" ) + sut.updateProfile("userId", "test@email.com", null, null, "testuser") throw RuntimeException("unreachable code") } catch (ex: Exception) { assertThat(ex, isEqualTo(instanceOf(RocketChatApiException::class.java))) @@ -163,7 +163,7 @@ class UserTest { } @Test - fun `updateOwnBasicInformation() should succeed with valid parameters` () { + fun `updateOwnBasicInformation() should succeed with valid parameters`() { mockServer.expect() .post() .withPath("/api/v1/users.updateOwnBasicInfo") @@ -207,7 +207,7 @@ class UserTest { runBlocking { try { - sut.updateOwnBasicInformation("userId", "test@email.com", null, null, "testuser" ) + sut.updateOwnBasicInformation("userId", "test@email.com", null, null, "testuser") throw RuntimeException("unreachable code") } catch (ex: Exception) { assertThat(ex, isEqualTo(instanceOf(RocketChatApiException::class.java))) @@ -219,7 +219,7 @@ class UserTest { } @Test - fun `deleteOwnAccount() should succeed with valid parameters` () { + fun `deleteOwnAccount() should succeed with valid parameters`() { mockServer.expect() .post() .withPath("/api/v1/users.deleteOwnAccount") @@ -233,7 +233,7 @@ class UserTest { } @Test(expected = RocketChatException::class) - fun `deleteOwnAccount() should fail with RocketChatAuthException if not logged in` () { + fun `deleteOwnAccount() should fail with RocketChatAuthException if not logged in`() { mockServer.expect() .post() .withPath("/api/v1/users.deleteOwnAccount") diff --git a/dependencies.gradle b/dependencies.gradle index 9cd00ceb..b9522614 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,11 +1,11 @@ ext { versions = [ - kotlin : '1.2.71', - kotlinter : '1.11.2', - coroutine : '0.25.0', + kotlin : '1.3.21', + kotlinter : '1.22.0', + coroutine : '1.1.1', dokka : '0.9.17', - kotshi : '1.0.5', - okhttp : '3.11.0', - moshi : '1.6.0' + kotshi : '1.0.6', + okhttp : '3.13.1', + moshi : '1.8.0' ] -} +} \ No newline at end of file diff --git a/rxjava/build.gradle b/rxjava/build.gradle deleted file mode 100644 index 1fa9e4d6..00000000 --- a/rxjava/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -group 'chat.rocket.sdk' -version '0.1-SNAPSHOT' - -apply from: rootProject.file('dependencies.gradle') - -apply plugin: 'kotlin' -apply plugin: 'java' -apply plugin: 'org.jetbrains.dokka' - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}" - - compile 'io.reactivex.rxjava2:rxjava:2.1.6' - compile 'io.reactivex.rxjava2:rxkotlin:2.1.0' - compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.coroutine}" - compile "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:${versions.coroutine}" - - compile project (':core') - - testCompile "org.jetbrains.kotlin:kotlin-test-junit:${versions.kotlin}" - testCompile "org.jetbrains.kotlin:kotlin-reflect:${versions.kotlin}" - testCompile 'junit:junit:4.12' - testCompile 'org.mockito:mockito-core:2.10.0' - testCompile 'org.assertj:assertj-core:3.8.0' - testCompile "com.nhaarman:mockito-kotlin-kt1.1:1.5.0" - testCompile 'com.github.luciofm:mockwebserver:852ce0b657' -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/javadoc" -} \ No newline at end of file diff --git a/rxjava/src/main/kotlin/chat/rocket/core/rxjava/Login.kt b/rxjava/src/main/kotlin/chat/rocket/core/rxjava/Login.kt deleted file mode 100644 index 1cffbdb2..00000000 --- a/rxjava/src/main/kotlin/chat/rocket/core/rxjava/Login.kt +++ /dev/null @@ -1,46 +0,0 @@ -package chat.rocket.core.rxjava - -import chat.rocket.common.model.Token -import chat.rocket.common.model.User -import chat.rocket.core.RocketChatClient -import chat.rocket.core.internal.rest.login -import chat.rocket.core.internal.rest.signup -import io.reactivex.Single -import kotlinx.coroutines.experimental.rx2.rxSingle - -/** - * Login with username and password. On success this will also call [chat.rocket.core.TokenRepository].save(token) - * - * @param username Username - * @param password Password - * @return [Single]<[Token]> - * @see Token - * @see chat.rocket.core.TokenRepository - * - * @sample - */ -fun RocketChatClient.login(username: String, password: String): Single = - rxSingle { - login(username, password) - } - -/** - * Registers a new user within the server. - * - * Note, this doesn't authenticate the user. after a successful registration you still need to - * call [login] - * - * @param email Email - * @param name Name - * @param username Username - * @param password Password - * @return [Single]<[User]> - * @see User - */ -fun RocketChatClient.signup(email: String, - name: String, - username: String, - password: String): Single = - rxSingle { - signup(email, name, username, password) - } \ No newline at end of file diff --git a/rxjava/src/main/kotlin/chat/rocket/core/rxjava/User.kt b/rxjava/src/main/kotlin/chat/rocket/core/rxjava/User.kt deleted file mode 100644 index dff1f930..00000000 --- a/rxjava/src/main/kotlin/chat/rocket/core/rxjava/User.kt +++ /dev/null @@ -1,12 +0,0 @@ -package chat.rocket.core.rxjava - -import chat.rocket.core.RocketChatClient -import chat.rocket.core.internal.rest.me -import chat.rocket.core.model.Myself -import io.reactivex.Single -import kotlinx.coroutines.experimental.rx2.rxSingle - -fun RocketChatClient.me(): Single = - rxSingle { - me() - } \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 83f62ff3..d628c34e 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -21,7 +21,6 @@ dependencies { compile project (':common') compile project (':core') - compile project (':rxjava') compile project (':compat') compile 'com.squareup.okhttp3:logging-interceptor:3.9.0' @@ -36,9 +35,3 @@ compileKotlin { compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } - -kotlin { - experimental { - coroutines "enable" - } -} \ No newline at end of file diff --git a/sample/src/main/kotlin/rocket/chat/kotlin/sample/Sample.kt b/sample/src/main/kotlin/rocket/chat/kotlin/sample/Sample.kt index 9ee34815..f756dfc3 100644 --- a/sample/src/main/kotlin/rocket/chat/kotlin/sample/Sample.kt +++ b/sample/src/main/kotlin/rocket/chat/kotlin/sample/Sample.kt @@ -4,7 +4,6 @@ import chat.rocket.common.RocketChatException import chat.rocket.common.model.RoomType import chat.rocket.common.model.ServerInfo import chat.rocket.common.model.Token -import chat.rocket.common.model.UserStatus import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient import chat.rocket.core.TokenRepository @@ -13,27 +12,17 @@ import chat.rocket.core.compat.serverInfo import chat.rocket.core.internal.realtime.* import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.connect -import chat.rocket.core.internal.rest.chatRooms -import chat.rocket.core.internal.rest.getFavoriteMessages -import chat.rocket.core.internal.rest.getFiles -import chat.rocket.core.internal.rest.login -import chat.rocket.core.model.Myself +import chat.rocket.core.internal.rest.* import chat.rocket.core.model.history import chat.rocket.core.model.messages -import chat.rocket.core.rxjava.me -import io.reactivex.Single -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.channels.Channel -import kotlinx.coroutines.experimental.delay -import kotlinx.coroutines.experimental.launch -import kotlinx.coroutines.experimental.runBlocking -import kotlinx.coroutines.experimental.suspendCancellableCoroutine +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import java.util.concurrent.TimeUnit fun main(args: Array) { + val logger = object : PlatformLogger { override fun debug(s: String) { println(s) @@ -58,38 +47,30 @@ fun main(args: Array) { val client = RocketChatClient.create { httpClient = okHttpClient - restUrl = "https://unstable.rocket.chat" + restUrl = "https://your-server.rocket.chat" userAgent = "Rocket.Chat.Kotlin.SDK" tokenRepository = SimpleTokenRepository() platformLogger = logger } - // using coroutines - val job = launch(CommonPool) { - - val token = client.login("luciofm-testing", "vpnfe5lnv!") + val job = GlobalScope.launch(Dispatchers.IO) { + val token = client.login("your-username", "your-password") logger.debug("Token: userId = ${token.userId} - authToken = ${token.authToken}") launch { val statusChannel = Channel() client.addStateChannel(statusChannel) for (status in statusChannel) { - logger.debug("Changing status to: $status") - when (status) { - is State.Authenticating -> { - logger.debug("Authenticating") - } - is State.Connected -> { - logger.debug("Connected") + logger.debug("CHANGING STATUS TO: $status") + if (status is State.Connected) { + logger.debug("Connected!") client.subscribeSubscriptions { _, _ -> } client.subscribeRooms { _, _ -> } -// client.subscribeUserData { _, _ -> } -// client.subscribeActiveUsers { _, _ -> } -// client.subscribeTypingStatus("GENERAL") {_, _ -> } - } + client.subscribeUserData { _, _ -> } + client.subscribeActiveUsers { _, _ -> } + client.subscribeTypingStatus("GENERAL") {_, _ -> } } } - logger.debug("Done on statusChannel") } launch { @@ -127,41 +108,32 @@ fun main(args: Array) { // client.setTemporaryStatus(UserStatus.Online()) // delay(2000) // client.setDefaultStatus(UserStatus.Away()) -// client.setTypingStatus("GENERAL", "luciofm-testing", true) +// client.setTypingStatus("GENERAL", "testing", true) showFileList(client) } client.connect() + logger.debug("PERMISSIONS: ${client.permissions()}") /* client.sendMessage(roomId = "GENERAL", text = "Sending message from SDK to #general and @here with url https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK/", alias = "TestingAlias", emoji = ":smirk:", avatar = "https://avatars2.githubusercontent.com/u/224255?s=88&v=4") - - pinMessage(client)*/ - - //getMeInfoByRx(client) +*/ val rooms = client.chatRooms() - logger.debug("ChatRooms: $rooms") + logger.debug("CHAT ROOMS: $rooms") val room = rooms.update.lastOrNull { room -> room.id.contentEquals("GENERAL") } - logger.debug("Room: $room") - val messages = room?.messages() - messages?.let { - logger.debug("Messages: $messages") - } - - val messages2 = room?.history() - messages2?.let { - logger.debug("Messages2: $messages2") - } + logger.debug("ROOM: $room") + logger.debug("MESSAGES: ${room?.messages()}") + logger.debug("HISTORY: ${room?.history()}") } // simple old callbacks client.serverInfo(object : Callback { override fun onSuccess(data: ServerInfo) { - logger.debug("Server: $data") + logger.debug("SERVER INFO: $data") } override fun onError(error: RocketChatException) { @@ -178,17 +150,6 @@ fun main(args: Array) { } } -fun getMeInfoByRx(client: RocketChatClient) { - // using RxJava2 - val myself: Single = client.me() - myself - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.newThread()) - .subscribe { self -> - println("Self: $self") - } -} - suspend fun showFavoriteMessage(client: RocketChatClient) { val result = client.getFavoriteMessages("GENERAL", RoomType.Channel(), 0) println("favoriteMessages: $result")