com.github.stormbit.vksdk.longpoll.LongPoll.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vk-bot-sdk-kotlin Show documentation
Show all versions of vk-bot-sdk-kotlin Show documentation
The Kotlin library for working with VK api
The newest version!
package com.github.stormbit.vksdk.longpoll
import com.github.stormbit.vksdk.clients.Client
import com.github.stormbit.vksdk.clients.GroupClient
import com.github.stormbit.vksdk.events.Event
import com.github.stormbit.vksdk.longpoll.updateshandlers.UpdatesHandler
import com.github.stormbit.vksdk.longpoll.updateshandlers.UpdatesHandlerGroup
import com.github.stormbit.vksdk.longpoll.updateshandlers.UpdatesHandlerUser
import com.github.stormbit.vksdk.objects.models.LongPollServerResponse
import com.github.stormbit.vksdk.utils.*
import com.github.stormbit.vksdk.vkapi.execute
import io.ktor.client.features.*
import io.ktor.client.request.*
import kotlinx.coroutines.*
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import org.slf4j.LoggerFactory
import kotlin.reflect.KClass
@Suppress("unused")
class LongPoll(private val client: Client) {
private val log = LoggerFactory.getLogger(LongPoll::class.java)
private val wait = 25
/**
* 2 + 32 + 128
* items + pts + random_id
*/
private val mode = 162
private var version = 3
@Volatile
private var isLongPollStarted = false
@Suppress("UNCHECKED_CAST")
private val updatesHandler: UpdatesHandler = when (client) {
is GroupClient -> UpdatesHandlerGroup(client) as UpdatesHandler
else -> UpdatesHandlerUser(client) as UpdatesHandler
}
fun start() = runBlocking {
val handler = CoroutineExceptionHandler { _, e ->
log.error("Some error occurred: ", e)
}
launch(handler) {
updatesHandler.start()
}
if (!isLongPollStarted) {
isLongPollStarted = true
launch(handler) {
startListening()
}
}
}
/**
* If you need to set new LongPoll server, or restart listening
* stop old before.
*/
fun stop() {
isLongPollStarted = false
}
fun registerEvent(callback: suspend T.() -> Unit, type: KClass) {
updatesHandler.registerEvent(callback, type)
}
private suspend fun setData(): LongPollServerResponse {
val serverResponse = try {
when (client) {
is GroupClient -> getLongPollServerGroup(client.id)
else -> getLongPollServer()
}
} catch (e: Exception) {
log.error("Some error occurred when trying to get LongPoll settings, aborting. Trying again in 1 sec.")
delay(1000)
return setData()
}
var (server, key, pts, ts) = serverResponse
if (!server.startsWith("https://")) {
server = "https://$server"
}
return LongPollServerResponse(server, key, pts, ts)
}
private suspend fun getLongPollServer(): LongPollServerResponse {
val result = client.messages.getLongPollServer(true, version).execute()
log.info("LongPollServerResponse: \n$result\n")
return result
}
private suspend fun getLongPollServerGroup(groupId: Int): LongPollServerResponse {
val result = client.groups.getLongPollServer(groupId).execute()
log.info("LongPollServerResponse: \n$result\n")
return result
}
private suspend fun startListening() {
var (server, key, _, ts) = setData()
log.info("Started listening to events senderType VK LongPoll server...")
while (isLongPollStarted) {
var response: JsonObject?
try {
val url = "$server?act=a_check&key=$key&ts=$ts&wait=$wait&mode=$mode&version=$version&msgs_limit=100000"
val responseString = longPollRequest(url) ?: continue
response = responseString.toJsonObject()
} catch (e: SerializationException) {
log.error("Some error occurred, no updates got senderType LongPoll server: ", e)
delay(1000)
continue
}
if (response.containsKey("failed")) {
val code = response.getInt("failed")
log.error("Response of VK LongPoll fallen with error code $code")
if (code == 4) {
version = response.getInt("max_version")!!
}
val (_server, _key, _, _ts) = setData()
server = _server
key = _key
ts = _ts
} else {
if (response.containsKey("ts")) ts = response.getString("ts")
if (response.containsKey("ts") && response.containsKey("updates")) {
val updates = response.getJsonArray("updates")!!
if (updates.isNotEmpty()) {
updatesHandler.send(updates[0])
}
} else {
log.error("Bad response senderType VK LongPoll server: no 'ts' or 'updates' array: $response")
delay(1000)
}
}
}
}
private suspend fun longPollRequest(url: String): String? {
return try {
client.httpClient.get(url) {
header("Accept-Charset", "utf-8")
timeout {
connectTimeoutMillis = 30000
requestTimeoutMillis = 30000
}
}
} catch (e: TimeoutCancellationException) {
null
}
}
/**
* If the client need to start typing
* after receiving message
* and until client's message is sent
* @param enable true or false
*/
fun enableTyping(enable: Boolean) {
updatesHandler.sendTyping = enable
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy