com.github.stormbit.sdk.objects.Message.kt Maven / Gradle / Ivy
package com.github.stormbit.sdk.objects
import com.github.stormbit.sdk.callbacks.Callback
import com.github.stormbit.sdk.clients.Client
import com.github.stormbit.sdk.clients.Group
import com.github.stormbit.sdk.utils.*
import com.github.stormbit.sdk.utils.vkapi.API
import com.github.stormbit.sdk.utils.vkapi.Upload
import com.github.stormbit.sdk.utils.vkapi.docs.DocTypes
import com.github.stormbit.sdk.utils.vkapi.keyboard.Keyboard
import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import org.slf4j.LoggerFactory
import java.util.concurrent.CopyOnWriteArrayList
import java.util.regex.Pattern
@Suppress("unused", "MemberVisibilityCanBePrivate")
class Message {
private val log = LoggerFactory.getLogger(Message::class.java)
private val gson = Gson()
var messageId: Int? = null
private set
val from: MessageFrom?
get() {
return getSenderType(peerId)
}
var timestamp: Int = 0
private set
var chatId: Int = 0
var chatIdLong: Int = 0
var peerId: Int = 0
var randomId: Int = 0
var stickerId: Int = 0
var keyboard: Keyboard? = null
private var payload: JsonObject? = JsonObject()
private set(value) {
field = value ?: JsonObject()
}
var text: String = ""
var textWithoutCommand: String = text
get() {
val words = text.split(" ")
return if (words.size > 1) {
words.subList(1, words.size).joinToString(" ")
} else {
""
}
}
private set
var title: String = ""
private lateinit var api: API
private lateinit var upload: Upload
private lateinit var client: Client
/**
* Attachments in format of received event from longpoll server
*
* More: [link](https://vk.com/dev/using_longpoll_2)
*/
var attachmentsOfReceivedMessage: JsonObject? = JsonObject()
private set(value) {
field = value ?: JsonObject()
}
/**
* Attachments in format [photo62802565_456241137, photo111_111, doc100_500]
*/
private var attachments: CopyOnWriteArrayList = CopyOnWriteArrayList()
private var forwardedMessages: CopyOnWriteArrayList = CopyOnWriteArrayList()
private val photosToUpload = CopyOnWriteArrayList()
private val docsToUpload = CopyOnWriteArrayList()
var stringPhotos = ArrayList()
var stringDocs = ArrayList()
var stringVideos = ArrayList()
var stringAudios = ArrayList()
/**
* Constructor for sent message
*/
constructor()
/**
* Constructor for received message
*
* @param client client
* @param messageId message id
* @param peerId peer id
* @param timestamp timestamp
* @param text message text
* @param attachments message attachments
* @param randomId random id
*/
constructor(client: Client, messageId: Int, peerId: Int, timestamp: Int, text: String, title: String, attachments: JsonObject?, randomId: Int, payload: JsonObject?) {
this.messageId = messageId
this.peerId = peerId
this.timestamp = timestamp
this.text = text
this.attachmentsOfReceivedMessage = attachments
this.randomId = randomId
this.payload = payload
this.title = title
this.client = client
this.api = client.api
this.upload = Upload(client)
}
constructor(client: Client, json: JsonObject) {
this.client = client
this.api = client.api
this.upload = Upload(client)
this.messageId = json.getInt("id")
this.peerId = json.getInt("from_id")
this.timestamp = json.getInt("date")
this.text = json.getString("text")
this.randomId = json.getInt("random_id")
this.payload = if (json.has("payload")) gson.toJsonTree(json.getString("payload")).asJsonObject else JsonObject()
this.title = " ... "
val attachments = if (json.getAsJsonArray("attachments").size() > 0) json.getAsJsonArray("attachments").getJsonObject(0) else JsonObject()
// Check for chat
if (this.peerId > Chat.CHAT_PREFIX) {
this.chatId = this.peerId - Chat.CHAT_PREFIX
if (attachments.keySet().size > 0) {
this.peerId = attachments.getString("from").toInt()
}
this.messageId = json.getInt("conversation_message_id")
}
this.attachmentsOfReceivedMessage = attachments
if (chatId > 0) {
this.chatIdLong = Chat.CHAT_PREFIX + chatId
}
}
constructor(block: Message.() -> Message) {
block()
}
/**
* Your client with id
*
* @param client client
* @return this
*/
fun from(client: Client): Message {
api = client.api
upload = Upload(client)
this.client = client
return this
}
/**
* ID of target dialog
*
* @param peerId target
* @return this
*/
fun to(peerId: Int): Message {
this.peerId = peerId
return this
}
/**
* ID of sticker
*
* @param id sticker id
* @return this
*/
fun sticker(id: Int): Message {
this.stickerId = id
return this
}
/**
* IDs of forwarded messages
*
* @param ids message ids
* @return this
*/
fun forwardedMessages(vararg ids: String): Message {
forwardedMessages.addAllAbsent(ids.toList())
return this
}
/**
* Message text
*
* @param text message content
* @return this
*/
fun text(text: String): Message {
this.text = text
return this
}
/**
* Message title (bold text)
*
* @param title message title
* @return this
*/
fun title(title: String): Message {
this.title = title
return this
}
/**
* Message keyboard
*
* @param keyboard keyboard
* @return this
*/
fun keyboard(keyboard: Keyboard): Message {
this.keyboard = keyboard
return this
}
/**
* Message attachments
* @param attachments attachments
* @return this
*/
fun attachments(vararg attachments: String): Message {
if (attachments.size > 10) log.error("Trying to send message with illegal count of attachments: {} (> 10)", attachments.size) else if (attachments.size == 1 && attachments[0].contains(",")) {
this.attachments.addAllAbsent(listOf(*attachments[0].split(",".toRegex()).toTypedArray()))
} else {
this.attachments.addAllAbsent(listOf(*attachments))
}
return this
}
/**
* Message random_id
*
* @param randomId random_id
* @return this
*/
fun randomId(randomId: Int): Message {
this.randomId = randomId
return this
}
/**
* Message sticker_id
*
* @param stickerId sticker_id
* @return this
*/
fun stickerId(stickerId: Int): Message {
this.stickerId = stickerId
return this
}
/**
* @param photo String URL, link to vk doc or path to file
* @return this
*/
fun photo(photo: String): Message {
if (Regex("[https://vk.com]?photo-?\\d+_\\d+").matches(photo)) {
attachments.add(photo.substring(photo.lastIndexOf("photo")))
return this
}
attachments.add(upload.uploadPhoto(photo, peerId))
return this
}
/**
* Synchronous adding doc to the message
*
* @param doc String URL, link to vk doc or path to file
* @return this
*/
fun doc(doc: String): Message {
val docAsAttach = upload.uploadDoc(doc, peerId, DocTypes.DOC)
if (docAsAttach != null) attachments.add(docAsAttach)
return this
}
/**
* Attach photo to message
*
*
* Works slower that sync photo adding, but will be called from execute
*
* @param photo Photo link: url, from disk or already uploaded to VK as photo{owner_id}_{id}
* @return this
*/
fun photoAsync(photo: String): Message {
// Use already loaded photo
if (Pattern.matches("[htps:/vk.com]?photo-?\\d+_\\d+", photo)) {
attachments.add(photo.substring(photo.lastIndexOf("photo")))
return this
}
// Use photo from url of disc
photosToUpload.add(photo)
return this
}
/**
* Attach doc to message
*
* @param doc Doc link: url, from disk or already uploaded to VK as doc{owner_id}_{id}
* @param type type
* @return this
*/
fun docAsync(doc: String, type: DocTypes): Message {
// Use already loaded photo
if (Pattern.matches("[htps:/vk.com]?doc-?\\d+_\\d+", doc)) {
attachments.add(doc)
return this
}
docsToUpload.add(JsonObject().put("doc", doc).put("type", type.type))
return this
}
/**
* Attach doc to message
*
* @param doc Doc link: url, from disk or already uploaded to VK as doc{owner_id}_{id}
* @return this
*/
fun docAsync(doc: String): Message {
this.docAsync(doc, DocTypes.DOC)
return this
}
/**
* Send voice message
*
* @param doc URL or path to file
* @param callback response will returns to callback
*/
fun sendVoiceMessage(doc: String, callback: Callback?) {
val docAsAttach = upload.uploadDoc(doc, peerId, DocTypes.AUDIO_MESSAGE)
if (docAsAttach != null) attachments.add(docAsAttach)
send(callback)
}
/**
* Send the message
*
*/
fun sendAsync(): JsonObject? {
if (photosToUpload.size > 0) {
val photo = photosToUpload[0]
photosToUpload.removeAt(0)
val response = upload.uploadPhoto(photo, peerId)
if (response != null) {
attachments.addIfAbsent(response.toString())
sendAsync()
} else log.error("Some error occurred when uploading photo.")
return null
}
if (docsToUpload.size > 0) {
val doc = docsToUpload[0]
docsToUpload.removeAt(0)
val response = upload.uploadDoc(doc.getString("doc"), peerId)
if (response != null) {
attachments.addIfAbsent(response.toString())
sendAsync()
} else log.error("Some error occurred when uploading photo.")
return null
}
return client.messages.send(
peerId = peerId,
randomId = randomId,
text = text,
stickerId = stickerId,
payload = payload.toString(),
attachments = attachments,
keyboard = keyboard)
}
fun send(callback: Callback? = null) {
if (photosToUpload.size > 0) {
val photo = photosToUpload[0]
photosToUpload.removeAt(0)
upload.uploadPhotoAsync(photo, peerId) { response: Any? ->
if (response != null) {
attachments.addIfAbsent(response.toString())
send(callback)
} else {
log.error("Some error occurred when uploading photo.")
}
}
return
}
if (docsToUpload.size > 0) {
val doc = docsToUpload[0]
docsToUpload.removeAt(0)
upload.uploadDocAsync(doc.getString("doc"), peerId) { response ->
if (response != null) {
attachments.addIfAbsent(response.toString())
send(callback)
} else {
log.error("Some error occurred when uploading doc.")
}
}
return
}
val response = client.messages.send(
peerId = peerId,
randomId = randomId,
text = text,
stickerId = stickerId,
payload = payload.toString(),
attachments = attachments,
keyboard = keyboard)
callback?.onResult(response)
}
/**
* Get the type of message
* @return type of message
*/
fun messageType(): MessageType? {
return when {
isVoiceMessage() -> MessageType.VOICE
isStickerMessage() -> MessageType.STICKER
isAudioMessage() -> MessageType.AUDIO
isVideoMessage() -> MessageType.VIDEO
isDocMessage() -> MessageType.DOC
isWallMessage() -> MessageType.WALL
isPhotoMessage() -> MessageType.PHOTO
isLinkMessage() -> MessageType.PHOTO
isSimpleTextMessage() -> MessageType.SIMPLE_TEXT
else -> null
}
}
/**
* @return true if message has forwarded messages
*/
fun hasFwds(): Boolean {
var answer = false
if (attachmentsOfReceivedMessage!!.has("fwd")) answer = true
return answer
}
/**
* @return array of forwarded messages or []
*/
fun getForwardedMessages(): JsonArray {
if (hasFwds()) {
val response = client.messages.getById(listOf(messageId!!))
if (response.has("response") && response.getAsJsonObject("response").getAsJsonArray("items").getJsonObject(0).has("fwd_messages")) {
return response.getAsJsonObject("response").getAsJsonArray("items").getJsonObject(0).getAsJsonArray("fwd_messages")
}
}
return JsonArray()
}
/**
* @return JsonObject with reply message or {}
*/
fun getReplyMessage(): JsonObject {
if (hasFwds()) {
val response = client.messages.getById(listOf(messageId!!))
if (response.has("response") && response.getAsJsonObject("response").getAsJsonArray("items").getJsonObject(0).has("reply_message")) {
return response.getAsJsonObject("response").getAsJsonArray("items").getJsonObject(0).getAsJsonObject("reply_message")
}
}
return JsonObject()
}
/**
* Get attachments from message
* @return JSONArray attachments
*/
fun getAttachments(): JsonArray {
val response: JsonObject = if (isMessageFromChat()) {
client.messages.getByConversationMessageId(chatIdLong, listOf(messageId!!), groupId = client.id)
} else {
client.messages.getById(listOf(messageId!!))
}
val stringPhotos = ArrayList()
val stringDocs = ArrayList()
val stringVideos = ArrayList()
val stringAudios = ArrayList()
if (response.has("response") && response.getAsJsonObject("response").getAsJsonArray("items").size() > 0) {
val items = response.getAsJsonObject("response").getAsJsonArray("items")
if (items.getJsonObject(0).has("attachments")) {
val attachs = items.getJsonObject(0).getAsJsonArray("attachments")
for (item in attachs) {
if (item is JsonObject) {
if (item.has("type")) {
when (item.getString("type")) {
"photo" -> {
val photo = item.getAsJsonObject("photo")
stringPhotos.add("photo${photo.getInt("owner_id")}_${photo.getInt("id")}")
}
"doc" -> {
val doc = item.getAsJsonObject("doc")
stringDocs.add("doc${doc.getInt("owner_id")}_${doc.getInt("id")}")
}
"video" -> {
val video = item.getAsJsonObject("video")
stringVideos.add("video${video.getInt("owner_id")}_${video.getInt("id")}")
}
"audio" -> {
val audio = item.getAsJsonObject("audio")
stringAudios.add("audio${audio.getInt("owner_id")}_${audio.getInt("id")}")
}
}
}
}
}
this.stringPhotos = stringPhotos
this.stringDocs = stringDocs
this.stringVideos = stringVideos
this.stringAudios = stringAudios
return attachs
}
}
return JsonArray()
}
/*
* Priority: voice, sticker, gif, ... , simple text
*/
fun isPhotoMessage(): Boolean = getCountOfAttachmentsByType()["photo"]!! > 0
fun isSimpleTextMessage(): Boolean = getCountOfAttachmentsByType()["summary"] == 0
fun isVoiceMessage(): Boolean = getCountOfAttachmentsByType()["voice"]!! > 0
fun isAudioMessage(): Boolean = getCountOfAttachmentsByType()["audio"]!! > 0
fun isVideoMessage(): Boolean = getCountOfAttachmentsByType()["video"]!! > 0
fun isDocMessage(): Boolean = getCountOfAttachmentsByType()["doc"]!! > 0
fun isWallMessage(): Boolean = getCountOfAttachmentsByType()["wall"]!! > 0
fun isStickerMessage(): Boolean = getCountOfAttachmentsByType()["sticker"]!! > 0
fun isLinkMessage(): Boolean = getCountOfAttachmentsByType()["link"]!! > 0
/**
* Method helps to identify kind of message
*
* @return Map: key=type of attachment, value=count of attachments, key=summary - value=count of all attachments.
*/
fun getCountOfAttachmentsByType(): HashMap {
var photo = 0
var video = 0
var audio = 0
var doc = 0
var wall = 0
var link = 0
val answer = HashMap()
answer["photo"] = 0
answer["video"] = 0
answer["audio"] = 0
answer["doc"] = 0
answer["wall"] = 0
answer["sticker"] = 0
answer["link"] = 0
answer["voice"] = 0
answer["summary"] = 0
if (attachmentsOfReceivedMessage.toString().contains("sticker")) {
answer["sticker"] = 1
answer["summary"] = 1
return answer
} else {
if (attachmentsOfReceivedMessage.toString().contains("audiomsg")) {
answer["voice"] = 1
answer["summary"] = 1
return answer
} else {
if (client is Group) {
for (key in attachmentsOfReceivedMessage!!.keySet()) {
if (key == "type") {
when (val value = attachmentsOfReceivedMessage!!.getString(key)) {
"photo" -> {
answer[value] = ++photo
}
"video" -> {
answer[value] = ++video
}
"audio" -> {
answer[value] = ++audio
}
"doc" -> {
answer[value] = ++doc
}
"wall" -> {
answer[value] = ++wall
}
"link" -> {
answer[value] = ++link
}
}
}
}
} else {
for (key in attachmentsOfReceivedMessage!!.keySet()) {
if (key.contains("type")) {
when (val value = attachmentsOfReceivedMessage!!.getString(key)) {
"photo" -> {
answer[value] = ++photo
}
"video" -> {
answer[value] = ++video
}
"audio" -> {
answer[value] = ++audio
}
"doc" -> {
answer[value] = ++doc
}
"wall" -> {
answer[value] = ++wall
}
"link" -> {
answer[value] = ++link
}
}
}
}
}
}
}
var summary = 0
for (key in answer.keys) {
if (answer[key]!! > 0) summary++
}
answer["summary"] = summary
return answer
}
/* Public getters */
fun getPhotos(): JsonArray? {
val attachments = getAttachments()
val answer = JsonArray()
for (i in 0 until attachments.size()) {
if (attachments.getJsonObject(i).getString("type").contains("photo")) answer.add(attachments.getJsonObject(i).getAsJsonObject("photo"))
}
return answer
}
/* Private setters */
fun getVoiceMessage(): JsonObject? {
val attachments = getAttachments()
var answer: JsonObject? = JsonObject()
for (i in 0 until attachments.size()) {
if (attachments.getJsonObject(i).getString("type").contains("doc") && attachments.getJsonObject(i).getAsJsonObject("doc").toString().contains("waveform")) answer = attachments.getJsonObject(i).getAsJsonObject("doc")
}
return answer
}
fun isMessageFromChat(): Boolean {
return chatId > 0 || chatIdLong > 0
}
private fun setAttachments(attachments: JsonObject?) {
if (attachments == null) return
attachmentsOfReceivedMessage = attachments
}
private fun getForwardedMessagesIds(): Array? {
return if (attachmentsOfReceivedMessage!!.has("fwd")) {
attachmentsOfReceivedMessage!!.getString("fwd").split(",".toRegex()).toTypedArray()
} else arrayOf()
}
private fun getSenderType(peerId: Int): MessageFrom? {
return when {
peerId.isGroupId -> MessageFrom.GROUP
peerId.isUserPeerId -> MessageFrom.USER
peerId.isChatPeerId -> MessageFrom.CHAT
else -> null
}
}
override fun toString(): String {
return '{'.toString() +
"\"message_id\":" + messageId +
",\"peer_id\":" + peerId +
",\"timestamp\":" + timestamp +
",\"random_id\":" + randomId +
",\"text\":\"" + text + '\"' +
",\"attachments\":" + attachmentsOfReceivedMessage.toString() +
",\"payload\":" + payload.toString() +
'}'
}
enum class MessageType {
PHOTO,
AUDIO,
VIDEO,
VOICE,
STICKER,
DOC,
WALL,
LINK,
SIMPLE_TEXT
}
enum class MessageFrom {
USER,
GROUP,
CHAT
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy