Skip to content

Commit

Permalink
Update Kotlin 1.5 branch to upstream (#292)
Browse files Browse the repository at this point in the history
* Implement voice stage channel (#239)

* compute All

* implement rest endpoints

* JSON representation

* implement core representation

* handle stage channels

* Apply suggestions

Co-authored-by: BartArys <mysterybtdn@gmail.com>

* Remove duplicated factory function
Co-authored-by: BartArys <mysterybtdn@gmail.com>

* add documentation

* Document the requestToSpeak variable

Co-authored-by: BartArys <mysterybtdn@gmail.com>

* Fix CI triggers

* Add "Competing" activity type (Fix #270) (#272)

* Make Updatestatus activities not-null (#274)

As per Discord's documentation: discord/discord-api-docs#2789

* Fix memory issues related to Permission combining (#277)

* Do not octuple bitset size on copy

the pure plus and minus function create a new array to work with, this incorrectly created an array of a size equal to the amount of bits that were allocated, instead the amount of longs. Thus, octupling the internal size.

* Optimize Permission All

The All Permission folded each DiscordBitSet of each value into eachother, resulting in n + 1 bitsets being created. This commit changes that to use the internal `add` which instead, which only mutates the single bitset created.

* Add Stream permission

It was missing

* Add Permission All regression tests

* Update deprecated message (#280)

* Expose the creation of application commands behavior (#281)

* Fix GuildUpdate core handling (#284)

* Expose the creation of application commands behavior

* Fix type of emitted event

* Sealed message types (#282)

* Expose the creation of application commands behavior

* Make message types sealed

* make Unknown a class

* Add missing message types

* make MessageTypeSerializer internal

* Add buttons to Activity (#287)

* Add buttons to Activity

* Also pass buttons in constructor

* Add missing fields to Guild (#288)

* Add missing fields to Guild
- Add welcome_screen
- Add nsfw

* Fix failing tests

* Fix another failing tests

* Add Message.applicationId (#289)

Co-authored-by: Hope <34831095+HopeBaron@users.noreply.github.com>
Co-authored-by: BartArys <mysterybtdn@gmail.com>
Co-authored-by: HopeBaron <truehope9000@gmail.com>
Co-authored-by: Bart Arys <BartArys@users.noreply.github.com>
Co-authored-by: Noah Hendrickson <noah@noahhendrickson.com>
  • Loading branch information
6 people authored May 14, 2021
1 parent dc7cdd1 commit d38dd7d
Show file tree
Hide file tree
Showing 40 changed files with 583 additions and 94 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/deployment-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ name: Kotlin CI

on:
push:
branches:
- '**' # We want to run this on all branch pushes
tags-ignore:
- '**' # We don't want this to run on tags pushes
branches:
Expand Down
4 changes: 2 additions & 2 deletions common/src/main/kotlin/DiscordBitSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ class DiscordBitSet(internal var data: LongArray) {
}

operator fun plus(another: DiscordBitSet): DiscordBitSet {
val dist = LongArray(size)
val dist = LongArray(data.size)
data.copyInto(dist)
val copy = DiscordBitSet(dist)
copy.add(another)
return copy
}

operator fun minus(another: DiscordBitSet): DiscordBitSet {
val dist = LongArray(size)
val dist = LongArray(data.size)
data.copyInto(dist)
val copy = DiscordBitSet(dist)
copy.remove(another)
Expand Down
6 changes: 4 additions & 2 deletions common/src/main/kotlin/entity/DiscordActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ data class DiscordActivity(
val assets: Optional<DiscordActivityAssets> = Optional.Missing(),
val secrets: Optional<DiscordActivitySecrets> = Optional.Missing(),
val instance: OptionalBoolean = OptionalBoolean.Missing,
val flags: Optional<ActivityFlags> = Optional.Missing()
val flags: Optional<ActivityFlags> = Optional.Missing(),
val buttons: Optional<List<String>> = Optional.Missing()
)

enum class ActivityFlag(val value: Int) {
Expand Down Expand Up @@ -136,7 +137,8 @@ enum class ActivityType(val code: Int) {
Streaming(1),
Listening(2),
Watching(3),
Custom(4);
Custom(4),
Competing(5);

companion object ActivityTypeSerializer : KSerializer<ActivityType> {
override val descriptor: SerialDescriptor
Expand Down
3 changes: 3 additions & 0 deletions common/src/main/kotlin/entity/DiscordChannel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ sealed class ChannelType(val value: Int) {
/** A channel in which game developers can sell their game on Discord. */
object GuildStore : ChannelType(6)

object GuildStageVoice : ChannelType(13)

companion object;

internal object Serializer : KSerializer<ChannelType> {
Expand All @@ -108,6 +110,7 @@ sealed class ChannelType(val value: Int) {
4 -> GuildCategory
5 -> GuildNews
6 -> GuildStore
13 -> GuildStageVoice
else -> Unknown(code)
}

Expand Down
7 changes: 6 additions & 1 deletion common/src/main/kotlin/entity/DiscordGuild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ data class DiscordUnavailableGuild(
* @param approximateMemberCount The approximate number of members in this guild, returned from the `GET /guild/<id>` endpoint when `with_counts` is `true`.
* @param approximatePresenceCount The approximate number of non-offline members in this guild, returned from the `GET /guild/<id>` endpoint when `with_counts` is `true`.
* @param welcomeScreen The welcome screen of a Community guild, shown to new members.
* @param nsfw true if this guild is [designated as NSFW](https://support.discord.com/hc/en-us/articles/1500005389362-NSFW-Server-Designation)
*/
@Serializable
data class DiscordGuild(
Expand Down Expand Up @@ -150,7 +151,9 @@ data class DiscordGuild(
val approximateMemberCount: OptionalInt = OptionalInt.Missing,
@SerialName("approximate_presence_count")
val approximatePresenceCount: OptionalInt = OptionalInt.Missing,

@SerialName("welcome_screen")
val welcomeScreen: Optional<DiscordWelcomeScreen> = Optional.Missing(),
val nsfw: Boolean
)

/**
Expand Down Expand Up @@ -372,6 +375,8 @@ data class DiscordVoiceState(
@SerialName("self_stream")
val selfStream: OptionalBoolean = OptionalBoolean.Missing,
val suppress: Boolean,
@SerialName("request_to_speak_timestamp")
val requestToSpeakTimestamp: String?
)

/**
Expand Down
78 changes: 58 additions & 20 deletions common/src/main/kotlin/entity/DiscordMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import kotlin.contracts.contract
* @param flags Message flags.
* @param stickers The stickers sent with the message (bots currently can only receive messages with stickers, not send).
* @param referencedMessage the message associated with [messageReference].
* @param applicationId if the message is a response to an [Interaction][DiscordInteraction], this is the id of the interaction's application
*/
@Serializable
data class DiscordMessage(
Expand Down Expand Up @@ -93,6 +94,8 @@ data class DiscordMessage(
val type: MessageType,
val activity: Optional<MessageActivity> = Optional.Missing(),
val application: Optional<MessageApplication> = Optional.Missing(),
@SerialName("application_id")
val applicationId: OptionalSnowflake = OptionalSnowflake.Missing,
@SerialName("message_reference")
val messageReference: Optional<DiscordMessageReference> = Optional.Missing(),
val flags: Optional<MessageFlags> = Optional.Missing(),
Expand Down Expand Up @@ -719,42 +722,77 @@ data class AllRemovedMessageReactions(
)

@Serializable(with = MessageType.MessageTypeSerializer::class)
enum class MessageType(val code: Int) {
sealed class MessageType(val code: Int) {
/** The default code for unknown values. */
Unknown(Int.MIN_VALUE),
Default(0),
RecipientAdd(1),
RecipientRemove(2),
Call(3),
ChannelNameChange(4),
ChannelIconChange(5),
ChannelPinnedMessage(6),
GuildMemberJoin(7),
UserPremiumGuildSubscription(8),
UserPremiumGuildSubscriptionTierOne(9),
UserPremiumGuildSubscriptionTwo(10),
UserPremiumGuildSubscriptionThree(11),
ChannelFollowAdd(12),
GuildDiscoveryDisqualified(14),
class Unknown(code: Int) : MessageType(code)
object Default : MessageType(0)
object RecipientAdd : MessageType(1)
object RecipientRemove : MessageType(2)
object Call : MessageType(3)
object ChannelNameChange : MessageType(4)
object ChannelIconChange : MessageType(5)
object ChannelPinnedMessage : MessageType(6)
object GuildMemberJoin : MessageType(7)
object UserPremiumGuildSubscription : MessageType(8)
object UserPremiumGuildSubscriptionTierOne : MessageType(9)
object UserPremiumGuildSubscriptionTwo : MessageType(10)
object UserPremiumGuildSubscriptionThree : MessageType(11)
object ChannelFollowAdd : MessageType(12)
object GuildDiscoveryDisqualified : MessageType(14)

@Suppress("SpellCheckingInspection")
GuildDiscoveryRequalified(15),
Reply(19);
object GuildDiscoveryRequalified : MessageType(15)
object GuildDiscoveryGracePeriodInitialWarning : MessageType(16)
object GuildDiscoveryGracePeriodFinalWarning : MessageType(17)
object ThreadCreated : MessageType(18)
object Reply : MessageType(19)
object ApplicationCommand : MessageType(20)
object ThreadStarterMessage : MessageType(21)
object GuildInviteReminder : MessageType(22)

companion object MessageTypeSerializer : KSerializer<MessageType> {
internal object MessageTypeSerializer : KSerializer<MessageType> {

override val descriptor: SerialDescriptor
get() = PrimitiveSerialDescriptor("type", PrimitiveKind.INT)

override fun deserialize(decoder: Decoder): MessageType {
val code = decoder.decodeInt()
return values().firstOrNull { it.code == code } ?: Unknown
return values.firstOrNull { it.code == code } ?: Unknown(code)
}

override fun serialize(encoder: Encoder, value: MessageType) {
encoder.encodeInt(value.code)
}
}

companion object {
val values: Set<MessageType>
get() = setOf(
Default,
RecipientAdd,
RecipientRemove,
Call,
ChannelNameChange,
ChannelIconChange,
ChannelPinnedMessage,
GuildMemberJoin,
UserPremiumGuildSubscription,
UserPremiumGuildSubscriptionTierOne,
UserPremiumGuildSubscriptionTwo,
UserPremiumGuildSubscriptionThree,
ChannelFollowAdd,
GuildDiscoveryDisqualified,
GuildDiscoveryRequalified,
Reply,
GuildDiscoveryGracePeriodInitialWarning,
GuildDiscoveryGracePeriodFinalWarning,
ThreadCreated,
ApplicationCommand,
ThreadStarterMessage,
GuildInviteReminder,

)
}
}

@Serializable(with = AllowedMentionType.Serializer::class)
Expand Down
8 changes: 6 additions & 2 deletions common/src/main/kotlin/entity/Permission.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.kord.common.entity

import dev.kord.common.DiscordBitSet
import dev.kord.common.EmptyBitSet
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
Expand All @@ -18,7 +19,7 @@ class Permissions constructor(val code: DiscordBitSet) {
/**
* Returns this [Permissions] as a [Set] of [Permission]
*/
val values = Permission.values.filter { it.code in code }.toSet()
val values = Permission.values.filter { it.code in code }.toSet()

operator fun plus(permission: Permission): Permissions = Permissions(code + permission.code)

Expand Down Expand Up @@ -130,6 +131,7 @@ sealed class Permission(val code: DiscordBitSet) {
object ManageGuild : Permission(0x00000020)
object AddReactions : Permission(0x00000040)
object ViewAuditLog : Permission(0x00000080)
object Stream : Permission(0x00000200)
object ViewChannel : Permission(0x00000400)
object SendMessages : Permission(0x00000800)
object SendTTSMessages : Permission(0x00001000)
Expand All @@ -153,7 +155,8 @@ sealed class Permission(val code: DiscordBitSet) {
object ManageWebhooks : Permission(0x20000000)
object ManageEmojis : Permission(0x40000000)
object UseSlashCommands : Permission(0x80000000)
object All : Permission(0xFFFFFDFF)
object RequestToSpeak : Permission(0x100000000)
object All : Permission(values.fold(EmptyBitSet()) { acc, value -> acc.add(value.code); acc })

companion object {
val values: Set<Permission>
Expand Down Expand Up @@ -189,6 +192,7 @@ sealed class Permission(val code: DiscordBitSet) {
ManageWebhooks,
ManageEmojis,
UseSlashCommands,
RequestToSpeak
)
}
}
1 change: 1 addition & 0 deletions common/src/test/kotlin/json/GuildTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class GuildTest {
preferredLocale shouldBe "en-US"
rulesChannelId shouldBe "441688182833020939"
publicUpdatesChannelId shouldBe "281283303326089216"
nsfw shouldBe true
}

}
Expand Down
17 changes: 15 additions & 2 deletions common/src/test/kotlin/json/PermissionsTest.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
package json

import dev.kord.common.DiscordBitSet
import dev.kord.common.entity.DiscordRole
import dev.kord.common.entity.Permissions
import dev.kord.common.EmptyBitSet
import dev.kord.common.entity.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import org.junit.jupiter.api.Test

class PermissionsTest {

@Test
fun `adding permissions together does not swallow the universe`() {
Permission.values.fold(Permissions(DiscordBitSet(0))) { acc, permission ->
acc + permission
}
}

@Test
fun `Permission All does not swallow the universe`() {
Permission.All //oh yeah, this is worthy of a test
}

@Test
fun `permissions serialization test`() {
val expected = buildJsonObject {
Expand Down
3 changes: 2 additions & 1 deletion common/src/test/resources/json/guild/guild.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@
"system_channel_flags": 0,
"preferred_locale": "en-US",
"rules_channel_id": "441688182833020939",
"public_updates_channel_id": "281283303326089216"
"public_updates_channel_id": "281283303326089216",
"nsfw": true
}
17 changes: 17 additions & 0 deletions core/src/main/kotlin/Unsafe.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dev.kord.common.annotation.KordUnsafe
import dev.kord.common.entity.Snowflake
import dev.kord.core.behavior.*
import dev.kord.core.behavior.channel.*
import dev.kord.rest.service.InteractionService

/**
* A class that exposes the creation of `{Entity}Behavior` classes.
Expand Down Expand Up @@ -71,4 +72,20 @@ class Unsafe(private val kord: Kord) {
return "Unsafe"
}

fun guildApplicationCommand(
guildId: Snowflake,
applicationId: Snowflake,
commandId: Snowflake,
service: InteractionService = kord.rest.interaction
): GuildApplicationCommandBehavior =
GuildApplicationCommandBehavior(guildId, applicationId, commandId, service)

fun globalApplicationCommand(
applicationId: Snowflake,
commandId: Snowflake,
service: InteractionService = kord.rest.interaction
): GlobalApplicationCommandBehavior =
GlobalApplicationCommandBehavior(applicationId, commandId, service)


}
33 changes: 33 additions & 0 deletions core/src/main/kotlin/behavior/GlobalApplicationCommandBehavior.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,37 @@ interface GuildApplicationCommandBehavior : ApplicationCommandBehavior {
override suspend fun delete() {
service.deleteGuildApplicationCommand(applicationId, guildId, id)
}

}

@KordPreview
fun GuildApplicationCommandBehavior(
guildId: Snowflake,
applicationId: Snowflake,
id: Snowflake,
service: InteractionService
): GuildApplicationCommandBehavior = object : GuildApplicationCommandBehavior {
override val guildId: Snowflake
get() = guildId
override val applicationId: Snowflake
get() = applicationId
override val service: InteractionService
get() = service
override val id: Snowflake
get() = id
}


@KordPreview
fun GlobalApplicationCommandBehavior(
applicationId: Snowflake,
id: Snowflake,
service: InteractionService
): GlobalApplicationCommandBehavior = object : GlobalApplicationCommandBehavior {
override val applicationId: Snowflake
get() = applicationId
override val service: InteractionService
get() = service
override val id: Snowflake
get() = id
}
26 changes: 26 additions & 0 deletions core/src/main/kotlin/behavior/channel/BaseVoiceChannelBehavior.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.kord.core.behavior.channel

import dev.kord.cache.api.query
import dev.kord.common.exception.RequestException
import dev.kord.core.cache.data.VoiceStateData
import dev.kord.core.cache.idEq
import dev.kord.core.entity.VoiceState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

interface BaseVoiceChannelBehavior : GuildChannelBehavior {

/**
* Requests to retrieve the present voice states of this channel.
*
* This property is not resolvable through REST and will always use [KordCache] instead.
*
* The returned flow is lazily executed, any [RequestException] will be thrown on
* [terminal operators](https://kotlinlang.org/docs/reference/coroutines/flow.html#terminal-flow-operators) instead.
*/
val voiceStates: Flow<VoiceState>
get() = kord.cache.query<VoiceStateData> { idEq(VoiceStateData::channelId, id) }
.asFlow()
.map { VoiceState(it, kord) }

}
Loading

0 comments on commit d38dd7d

Please sign in to comment.