Last active
July 31, 2020 14:15
-
-
Save mikef-dk/dcb5466a1dd8070577f808572159c3e0 to your computer and use it in GitHub Desktop.
Custom implementation of Scarlets' SocketIoClient but solves the following two issues: https://github.com/Tinder/Scarlet/issues/89 and https://github.com/Tinder/Scarlet/issues/145
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.tinder.scarlet.* | |
import com.tinder.scarlet.socketio.SocketIoEvent | |
import com.tinder.scarlet.utils.SimpleChannelFactory | |
import com.tinder.scarlet.utils.SimpleProtocolOpenRequestFactory | |
import io.socket.client.IO | |
import io.socket.client.Socket | |
import org.json.JSONArray | |
import org.json.JSONObject | |
class CustomSocketIoClient( | |
private val url: () -> String, | |
private val options: IO.Options = IO.Options() | |
) : Protocol { | |
override fun createChannelFactory(): Channel.Factory { | |
return SimpleChannelFactory { listener, _ -> | |
SocketIoMainChannel( | |
options, | |
listener | |
) | |
} | |
} | |
override fun createOpenRequestFactory(channel: Channel): Protocol.OpenRequest.Factory { | |
return SimpleProtocolOpenRequestFactory { | |
MainChannelOpenRequest(url()) | |
} | |
} | |
override fun createEventAdapterFactory(): ProtocolSpecificEventAdapter.Factory { | |
return SocketIoEvent.Adapter.Factory() | |
} | |
data class MainChannelOpenRequest(val url: String) : Protocol.OpenRequest | |
} | |
class SocketIoEventName( | |
private val eventName: String | |
) : Protocol { | |
override fun createChannelFactory(): Channel.Factory { | |
return SimpleChannelFactory { listener, parent -> | |
require(parent is SocketIoMainChannel) | |
SocketIoMessageChannel( | |
parent as SocketIoMainChannel, | |
eventName, | |
listener | |
) | |
} | |
} | |
override fun createEventAdapterFactory(): ProtocolSpecificEventAdapter.Factory { | |
return SocketIoEvent.Adapter.Factory() | |
} | |
} | |
internal class SocketIoMainChannel( | |
private val options: IO.Options, | |
private val listener: Channel.Listener | |
) : Channel { | |
var socket: Socket? = null | |
var openRequest: Protocol.OpenRequest? = null | |
var disconnected: Boolean = false | |
override fun open(openRequest: Protocol.OpenRequest) { | |
this.openRequest = openRequest | |
val mainChannelOpenRequest = openRequest as PfmSocketIoClient.MainChannelOpenRequest | |
val socket = IO.socket(mainChannelOpenRequest.url, options) | |
socket | |
.on(Socket.EVENT_CONNECT) { | |
listener.onOpened(this) | |
} | |
.on(Socket.EVENT_DISCONNECT) { | |
disconnected = true | |
listener.onClosed(this) | |
} | |
.on(Socket.EVENT_ERROR) { | |
listener.onFailed(this, true, null) | |
} | |
socket.open() | |
this.socket = socket | |
} | |
override fun close(closeRequest: Protocol.CloseRequest) { | |
socket?.disconnect() | |
socket = null | |
} | |
override fun forceClose() { | |
socket?.disconnect() | |
socket = null | |
} | |
override fun createMessageQueue(listener: MessageQueue.Listener): MessageQueue? { | |
return null | |
} | |
/** | |
* Tries to open the Socket again if a [Socket.EVENT_DISCONNECT] has been received | |
*/ | |
fun reconnect(): Socket? { | |
if (disconnected) { | |
disconnected = false | |
openRequest?.let { open(it) } | |
} | |
return socket | |
} | |
} | |
internal class SocketIoMessageChannel( | |
private val parent: SocketIoMainChannel, | |
private val eventName: String, | |
private val listener: Channel.Listener | |
) : Channel, MessageQueue { | |
private var socket: Socket? = null | |
private var messageQueueListener: MessageQueue.Listener? = null | |
override fun open(openRequest: Protocol.OpenRequest) { | |
socket = parent.socket | |
if (socket == null) { | |
socket = parent.reconnect() | |
if (socket == null) { | |
listener.onFailed(this, true, IllegalStateException("socket is null")) | |
return | |
} | |
} | |
socket?.on(eventName) { | |
val value = it[0] | |
when (value) { | |
is JSONObject -> { | |
messageQueueListener?.onMessageReceived( | |
this, this, | |
Message.Text(value.toString()) | |
) | |
} | |
is String -> { | |
messageQueueListener?.onMessageReceived( | |
this, this, | |
Message.Text(value.toString()) | |
) | |
} | |
is ByteArray -> { | |
messageQueueListener?.onMessageReceived( | |
this, this, | |
Message.Bytes(value) | |
) | |
} | |
is JSONArray -> { | |
messageQueueListener?.onMessageReceived( | |
this, this, | |
Message.Text(value.toString()) | |
) | |
} | |
} | |
} | |
listener.onOpened(this) | |
} | |
override fun close(closeRequest: Protocol.CloseRequest) { | |
socket?.off(eventName) | |
socket = null | |
listener.onClosed(this) | |
} | |
override fun forceClose() { | |
socket?.off(eventName) | |
socket = null | |
listener.onClosed(this) | |
} | |
override fun createMessageQueue(listener: MessageQueue.Listener): MessageQueue { | |
require(messageQueueListener == null) | |
messageQueueListener = listener | |
return this | |
} | |
override fun send(message: Message, messageMetaData: Protocol.MessageMetaData): Boolean { | |
val socket = socket ?: return false | |
when (message) { | |
is Message.Text -> socket.emit(eventName, message.value) | |
is Message.Bytes -> socket.emit(eventName, message.value) | |
} | |
return true | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment