K
Kord•2mo ago
Tic

Check if embed, actionRow etc. has been modified

Hello With the InteractionResponseModifyBuilder, we can define actionRow, embeds etc. However, I would like to avoid to send the same content to the API (to reduce network interaction) Need: So if my message had 2 embeds and 2 actionRows, but only the actionRows are modified since the last rendering, the request must send only the update about actionRows and not Embeds. So naively, I thought to verify with equals the old and new actionRows built, but that not works. For example
println(EmbedBuilder() == EmbedBuilder()) // false
println(EmbedBuilder().apply { title = "Hello" } == EmbedBuilder().apply { title = "Hello" }) // false
println(EmbedBuilder() == EmbedBuilder()) // false
println(EmbedBuilder().apply { title = "Hello" } == EmbedBuilder().apply { title = "Hello" }) // false
have you a better solution to do that?
58 Replies
gdude
gdude•2mo ago
Check each property manually That's how I did it in the KordEx welcome extension
Tic
Tic•2mo ago
We should create the equals method in kord, that should be more simple for everyone no?
gdude
gdude•2mo ago
it would, of course
Tic
Tic•2mo ago
@LustigerLurch @SchlaubiBus An opinion about that? (sorry I don't know who maintains hardly the project) If that's great for you, I will create a branch etc. to do that Have you the link of the files that your created for that? That could be helpful
Tic
Tic•2mo ago
Oh wow
LustigerLurch
LustigerLurch•2mo ago
Yes, we maintain Kord. As for comparing builders with builders or builders with entities, this seems like a hard thing to do for a few reasons: * It's not very clear to me how optionals vs. nullables should be compared (I have the feeling even Discord isn't really sure what means what for those). Is a null value and an Missing value considered equal? Kord builders are written to only expose nullable types but can be backed by an optional and nullable value that changes from Missing to null on first assignment. How do we handle this? * If we'd like our API to be consistent, implementing this would mean a lot of work to do for all builders (we'd have to implement equals and hashCode for a lot of classes). * There might be some property of some entity that isn't relevant for the comparison in every case, think of something like edited_timestamp for messages. How do we decide which to include? If possible I suggest to have some custom logic for this on your side instead, here is an idea how to do it: * Have a (data) class that represents the content of a message and use that data to "render" the actual message. * Keep a reference to an instance of that class representing the last sent message. You might also persist it somewhere if needed or reconstruct it from a message. * Use that to determine which parts need to be updated. I imagine something like this:
data class WelcomeMessage(
val content: String,
val rules: List<Rule>,
val links: List<Link>,
) {
data class Rule(val title: String, val description: String)
data class Link(val text: String, val url: String)
}

fun MessageBuilder.renderWelcomeMessage(message: WelcomeMessage, previous: WelcomeMessage? = null) {
if (message.content != previous?.content) {
content = message.content
}
if (message.rules != previous?.rules) {
for (rule in message.rules) {
embed {
title = rule.title
description = rule.description
color = ...
}
}
}
if (message.links != previous?.links) {
for (link in message.links) {
actionRow {
linkButton(link.url) {
label = link.text
}
}
}
}
}

// use it like this:
var currentMessageData = WelcomeMessage(...)
var message = channel.createMessage { renderWelcomeMessage(currentMessageData) }

// ...
val newMessageData = WelcomeMessage(...)
message = message.edit { renderWelcomeMessage(newMessageData, previous = currentMessageData) }
currentMessageData = newMessageData
data class WelcomeMessage(
val content: String,
val rules: List<Rule>,
val links: List<Link>,
) {
data class Rule(val title: String, val description: String)
data class Link(val text: String, val url: String)
}

fun MessageBuilder.renderWelcomeMessage(message: WelcomeMessage, previous: WelcomeMessage? = null) {
if (message.content != previous?.content) {
content = message.content
}
if (message.rules != previous?.rules) {
for (rule in message.rules) {
embed {
title = rule.title
description = rule.description
color = ...
}
}
}
if (message.links != previous?.links) {
for (link in message.links) {
actionRow {
linkButton(link.url) {
label = link.text
}
}
}
}
}

// use it like this:
var currentMessageData = WelcomeMessage(...)
var message = channel.createMessage { renderWelcomeMessage(currentMessageData) }

// ...
val newMessageData = WelcomeMessage(...)
message = message.edit { renderWelcomeMessage(newMessageData, previous = currentMessageData) }
currentMessageData = newMessageData
Tic
Tic•2mo ago
- Yes I think missing and null are similar, so the compare will not be harder. For the equal and hashcode, we just need to consider missing as null and all builder will match - That's true, but I think that could be a real benefits for developers. As you can see, I need this feature, in kordex too and I easily imagine that other devs need this for some components I can initialize this for all components and for the next time, we just need to maintain them in case of new fields (that will not be hard) - I imagine edited_timestamp is a field where the value is invented by Discord API and not the dev. In that case, we can create the basic equals for all fields and maybe a isSimilar method that ignores these types of fields. But in reality, the use of Equals and Hashcode will be used before sending a message, so only the fields defined by the dev will be present, in that case, if I have an object with toto and titi fields and defined values for both, I would like to compare all values not partially Yes that could be works If I create my own EmbedBuilder and transform it in the final step to a Kord.EmbedBuilder but if everyone needs to do that, that could be annoying for a lot of developer and I think a library should be easy to use to realize a common feature @LustigerLurch can I try to create a branch and will see what the result will be?
LustigerLurch
LustigerLurch•2mo ago
the thing is, you still will have to write some code similar to renderWelcomeMessage, that won't change
Tic
Tic•2mo ago
Yes but I think, I can handle it differently with equals and I would like to try it if possible
LustigerLurch
LustigerLurch•2mo ago
how would you do it?
Tic
Tic•2mo ago
For my app, for the moment I have different component (Embed, Button, Text, etc.) and each inject directly a new data in the dedicated builder So yes basically I can duplicate the builder structure but that's annoying and personal. Create equals will be helpful for everyone Honestly I don't understand the problem to do that, the equals and hashcode are common function present in all objects. So there is no specific difficulty to implement them
Tic
Tic•2mo ago
So yes for the moment, according to my app, I need to duplicate the code like that. The only advantage I see to do that in my side, is I can customize the builder to add function, but that's possible too with extension function and kord builder
Tic
Tic•2mo ago
And I need to do that for each used Kord builder. Instead of fix a equals & hashcode methods that don't work, I need to do that. That's a non sense ... It's preferable to fix the methods in the lib in my opinion
LustigerLurch
LustigerLurch•2mo ago
and how do you use these builders? and do you use the kord builders in their dsl form? if not, why? 👀
Want results from more Discord servers?
Add your server