Okhttp3 WebSocket簡單教程

package com.xiaomakj.jetpackplug.utils

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import com.google.gson.Gson
import com.xiaomakj.jetpackplug.App
import com.xiaomakj.jetpackplug.database.entity.BlazeMessage
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit

class ChatWebSocket(
    private val okHttpClient: OkHttpClient,
    private val context: Context
) : WebSocketListener() {

    private val failCode = 1000
    private val quitCode = 1001
    var connected: Boolean = false
    private var client: WebSocket? = null
    private val gson = Gson()

    companion object {
        const val WS_URL = "wss://xxx.xxx.xxx"
        val TAG = ChatWebSocket::class.java.simpleName
    }

    init {
        connected = false
    }

    @Synchronized
    fun connect() {
        if (client == null) {
            connected = false
            client = okHttpClient.newWebSocket(Request.Builder().url(WS_URL).build(), this)
        }
    }

    @Synchronized
    fun disconnect() {
        if (client != null) {
            closeInternal(quitCode)
            connectTimer?.dispose()
            client = null
            connected = false
        }
    }

    @Synchronized
    fun sendMessage(blazeMessage: BlazeMessage): BlazeMessage? {
        val bm: BlazeMessage? = null
        if (client != null && connected) {
            val result = client!!.send(gson.toJson(blazeMessage).gzip())
        } else {
            Log.e(TAG, "WebSocket not connect")
        }
        return bm
    }

    private fun sendPendingMessage() {
        client?.send(gson.toJson(BlazeMessage("", "")).gzip())
    }

    @Synchronized
    override fun onOpen(webSocket: WebSocket?, response: Response?) {
        if (client != null) {
            connected = true
            client = webSocket
            webSocketObserver?.onSocketOpen()
            connectTimer?.dispose()
            sendPendingMessage()
        }
    }

    override fun onMessage(webSocket: WebSocket?, bytes: ByteString?) {
        try {
            val json = bytes?.ungzip()
            val blazeMessage = gson.fromJson(json, BlazeMessage::class.java)
            handleReceiveMessage(blazeMessage)
        } catch (e: GzipException) {

        }
    }

    @SuppressLint("CheckResult")
    @Synchronized
    override fun onClosed(webSocket: WebSocket?, code: Int, reason: String?) {
        connected = false
        if (code == failCode) {
            closeInternal(code)
            if (connectTimer == null || connectTimer?.isDisposed == true) connectTimer =
                    Observable.interval(2000, TimeUnit.MILLISECONDS).subscribe {
                        if (App.instance.networkConnected()) {
                            connect()
                        }
                    }
        } else {
            webSocket?.cancel()
        }
    }

    private var connectTimer: Disposable? = null

    @Synchronized
    override fun onFailure(webSocket: WebSocket?, t: Throwable?, response: Response?) {
        t?.let {
            Log.e(TAG, "WebSocket onFailure ", it)
        }
        if (client != null) {
            if (t != null) {
                closeInternal(quitCode)
            } else {
                onClosed(webSocket, failCode, "OK")
            }
        }
    }

    private fun closeInternal(code: Int) {
        try {
            connected = false
            if (client != null) {
                client!!.close(code, "OK")
            }
        } catch (e: Exception) {

        } finally {
            client = null
            webSocketObserver?.onSocketClose()
        }
    }

    private fun handleReceiveMessage(blazeMessage: BlazeMessage) {

    }

    private fun makeMessageStatus(status: String, messageId: String) {

    }

    fun setWebSocketObserver(webSocketObserver: WebSocketObserver) {
        this.webSocketObserver = webSocketObserver
    }

    private var webSocketObserver: WebSocketObserver? = null

    interface WebSocketObserver {
        fun onSocketClose()
        fun onSocketOpen()
    }

}


@Throws(IOException::class)
fun String.gzip(): ByteString {
    val result = Buffer()
    val sink = Okio.buffer(GzipSink(result))
    sink.use {
        sink.write(toByteArray())
    }
    return result.readByteString()
}

fun ByteString.ungzip(): String {
    val buffer = Buffer().write(this)
    val gzip = GzipSource(buffer as Source)
    return Okio.buffer(gzip).readUtf8()
}

class GzipException : IOException()


fun Context.networkConnected(): Boolean {
    val cm = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        getSystemService(ConnectivityManager::class.java) ?: return false
    } else {
        return false
    }
    val network: NetworkInfo
    try {
        network = cm.activeNetworkInfo
    } catch (t: Throwable) {
        return false
    }
    return network != null && network.isConnected
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章