Yuito-app-android/app/src/main/java/net/accelf/yuito/streaming/MastodonStream.kt

91 lines
3.1 KiB
Kotlin

package net.accelf.yuito.streaming
import android.util.Log
import com.google.gson.Gson
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.appstore.StatusDeletedEvent
import com.keylesspalace.tusky.appstore.StreamUpdateEvent
import com.keylesspalace.tusky.entity.Filter
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import net.accelf.yuito.streaming.SubscribeRequest.RequestType.SUBSCRIBE
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
class MastodonStream(
coroutineScope: CoroutineScope,
private val okHttpClient: OkHttpClient,
private val gson: Gson,
private val eventHub: EventHub,
) : WebSocketListener(), CoroutineScope by coroutineScope {
private var webSocket: WebSocket? = null
fun openSocket(subscriptions: Set<Subscription>) {
val request = Request.Builder().url(STREAMING_URL).build()
webSocket = okHttpClient.newWebSocket(request, this)
subscriptions.forEach {
send(SubscribeRequest.fromSubscription(SUBSCRIBE, it))
Log.d(TAG, "Subscribed $it")
}
}
fun closeSocket() {
webSocket!!.close(1000, null)
webSocket = null
}
private fun send(subscribeRequest: SubscribeRequest) {
webSocket!!.send(gson.toJson(subscribeRequest))
}
override fun onOpen(webSocket: WebSocket, response: Response) {
Log.d(TAG, "Stream connected")
}
override fun onMessage(webSocket: WebSocket, text: String) {
val event = gson.fromJson(text, StreamEvent::class.java)
val payload = event.payload
when (event.event) {
StreamEvent.EventType.UPDATE -> {
val status = gson.fromJson(payload, Status::class.java)
launch {
eventHub.dispatch(StreamUpdateEvent(status, Subscription.fromStreamList(event.stream), this@MastodonStream.hashCode()))
}
}
StreamEvent.EventType.DELETE -> launch {
eventHub.dispatch(StatusDeletedEvent(payload))
}
StreamEvent.EventType.FILTERS_CHANGED -> launch {
eventHub.dispatch(PreferenceChangedEvent(Filter.Kind.HOME.kind)) // It may be not a home but it doesn't matter
}
else -> Log.d(TAG, "Unsupported event type.")
}
}
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
Log.d(TAG, "Stream closed")
}
companion object {
private const val TAG = "MastodonStream"
private val STREAMING_URL by lazy {
HttpUrl.Builder()
.scheme("https")
.host(MastodonApi.PLACEHOLDER_DOMAIN)
.addPathSegments("api/v1/streaming")
.build()
.toString()
.replace("https://", "wss://")
}
}
}