Skip to content

Commit c850c0b

Browse files
feat(message): add nonce support
1 parent 02efce5 commit c850c0b

File tree

5 files changed

+96
-44
lines changed

5 files changed

+96
-44
lines changed
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
//
2-
// File.swift
2+
// Snowflake+decode.swift
33
//
44
//
55
// Created by Vincent Kwok on 26/5/22.
66
//
77

88
import Foundation
99

10-
extension Snowflake {
10+
let DISCORD_EPOCH = 1420070400000
11+
12+
public extension Snowflake {
1113
/// Decodes this Snowflake into a Date
12-
public func decodeToDate() -> Date? {
14+
func decodeToDate() -> Date? {
1315
guard let intSnowflake = Int(self) else { return nil }
14-
let millisTimestamp = (intSnowflake >> 22) + 1420070400000
16+
let millisTimestamp = (intSnowflake >> 22) + DISCORD_EPOCH
1517
return Date(timeIntervalSince1970: Double(millisTimestamp) / 1000.0)
1618
}
1719
}

Sources/DiscordKitCore/Objects/Data/Message.swift

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public class Message: Codable, GatewayData, Identifiable {
8282
public static let ephemeral = Self(rawValue: 1 << 6)
8383
}
8484

85-
public init(id: Snowflake, channel_id: Snowflake, guild_id: Snowflake? = nil, author: User, member: Member? = nil, content: String, timestamp: Date, edited_timestamp: Date? = nil, tts: Bool, mention_everyone: Bool, mentions: [User], mention_roles: [Snowflake], mention_channels: [ChannelMention]? = nil, attachments: [Attachment], embeds: [Embed], reactions: [Reaction]? = nil, pinned: Bool, webhook_id: Snowflake? = nil, type: MessageType, activity: MessageActivity? = nil, application: Application? = nil, application_id: Snowflake? = nil, message_reference: MessageReference? = nil, flags: Int? = nil, referenced_message: Message? = nil, interaction: MessageInteraction? = nil, thread: Channel? = nil, components: [MessageComponent]? = nil, sticker_items: [StickerItem]? = nil) {
85+
public init(id: Snowflake, channel_id: Snowflake, guild_id: Snowflake? = nil, author: User, member: Member? = nil, content: String, timestamp: Date, edited_timestamp: Date? = nil, nonce: Nonce? = nil, tts: Bool, mention_everyone: Bool, mentions: [User], mention_roles: [Snowflake], mention_channels: [ChannelMention]? = nil, attachments: [Attachment], embeds: [Embed], reactions: [Reaction]? = nil, pinned: Bool, webhook_id: Snowflake? = nil, type: MessageType, activity: MessageActivity? = nil, application: Application? = nil, application_id: Snowflake? = nil, message_reference: MessageReference? = nil, flags: Int? = nil, referenced_message: Message? = nil, interaction: MessageInteraction? = nil, thread: Channel? = nil, components: [MessageComponent]? = nil, sticker_items: [StickerItem]? = nil, call: CallMessageComponent? = nil) {
8686
self.id = id
8787
self.channel_id = channel_id
8888
self.guild_id = guild_id
@@ -99,6 +99,7 @@ public class Message: Codable, GatewayData, Identifiable {
9999
self.attachments = attachments
100100
self.embeds = embeds
101101
self.reactions = reactions
102+
self.nonce = nonce
102103
self.pinned = pinned
103104
self.webhook_id = webhook_id
104105
self.type = type
@@ -112,6 +113,7 @@ public class Message: Codable, GatewayData, Identifiable {
112113
self.thread = thread
113114
self.components = components
114115
self.sticker_items = sticker_items
116+
self.call = call
115117
}
116118

117119
/// ID of the message
@@ -132,79 +134,80 @@ public class Message: Codable, GatewayData, Identifiable {
132134
/// > author object corresponds to the webhook's id, username, and avatar.
133135
/// > You can tell if a message is generated by a webhook by checking for
134136
/// > the webhook_id on the message object.
135-
public var author: User
137+
public let author: User
136138

137139
/// Member properties for this message's author
138-
public var member: Member?
140+
public let member: Member?
139141

140142
/// Contents of the message
141143
///
142144
/// Up to 2000 characters for non-premium users.
143-
public var content: String
145+
public let content: String
144146

145147
/// When this message was sent
146148
public let timestamp: Date
147149

148150
/// When this message was edited (or null if never)
149-
public var edited_timestamp: Date?
151+
public let edited_timestamp: Date?
150152

151153
/// If this was a TTS message
152-
public var tts: Bool
154+
public let tts: Bool
153155

154156
/// Whether this message mentions everyone
155-
public var mention_everyone: Bool
157+
public let mention_everyone: Bool
156158

157159
/// Users specifically mentioned in the message
158-
public var mentions: [User]
160+
public let mentions: [User]
159161

160162
/// Roles specifically mentioned in this message
161-
public var mention_roles: [Snowflake]
163+
public let mention_roles: [Snowflake]
162164

163165
/// Channels specifically mentioned in this message
164-
public var mention_channels: [ChannelMention]?
166+
public let mention_channels: [ChannelMention]?
165167

166168
/// Any attached files
167169
///
168170
/// See ``Attachment`` for more details.
169-
public var attachments: [Attachment]
171+
public let attachments: [Attachment]
170172

171173
/// Any embedded content
172174
///
173175
/// See ``Embed`` for more details
174-
public var embeds: [Embed]
176+
public let embeds: [Embed]
175177

176178
/// Reactions to the message
177-
public var reactions: [Reaction]?
178-
// Nonce can either be string or int and isn't important so I'm not including it for now
179+
public let reactions: [Reaction]?
180+
181+
public let nonce: Nonce?
179182

180183
/// If this message is pinned
181-
public var pinned: Bool
184+
public let pinned: Bool
182185

183186
/// If the message is generated by a webhook, this is the webhook's ID
184187
///
185188
/// Use this to check if the message is sent by a webhook. ``Message/author``
186189
/// will not be valid if this is not nil (was sent by a webhook).
187-
public var webhook_id: Snowflake?
190+
public let webhook_id: Snowflake?
188191

189192
/// Type of message
190193
///
191194
/// Refer to ``MessageType`` for possible values.
192195
public let type: MessageType
193196

194197
/// Sent with Rich Presence-related chat embeds
195-
public var activity: MessageActivity?
198+
public let activity: MessageActivity?
196199

197200
/// Sent with Rich Presence-related chat embeds
198-
public var application: Application?
201+
public let application: Application?
199202

200203
/// If the message is an Interaction or application-owned webhook, this is the ID of the application
201-
public var application_id: Snowflake?
204+
public let application_id: Snowflake?
202205

203206
/// Data showing the source of a crosspost, channel follow add, pin, or reply message
204-
public var message_reference: MessageReference?
207+
public let message_reference: MessageReference?
205208

206209
/// Message flags
207-
public var flags: Int?
210+
public let flags: Int?
208211

209212
/// The message associated with the message\_reference
210213
///
@@ -220,19 +223,19 @@ public class Message: Codable, GatewayData, Identifiable {
220223
public let referenced_message: Message?
221224

222225
/// Present if the message is a response to an Interaction
223-
public var interaction: MessageInteraction?
226+
public let interaction: MessageInteraction?
224227

225228
/// The thread that was started from this message, includes thread member object
226-
public var thread: Channel?
229+
public let thread: Channel?
227230

228231
/// Present if the message contains components like buttons, action rows, or other interactive components
229-
public var components: [MessageComponent]?
232+
public let components: [MessageComponent]?
230233

231234
/// Present if the message contains stickers
232-
public var sticker_items: [StickerItem]?
235+
public let sticker_items: [StickerItem]?
233236

234237
/// Present if the message is a call in DM
235-
public var call: CallMessageComponent?
238+
public let call: CallMessageComponent?
236239
}
237240

238241
/// A complete copy of ``Message`` but with most properties marked as Optional
@@ -274,19 +277,6 @@ public struct PartialMessage: Codable, GatewayData {
274277
public let sticker_items: [StickerItem]?
275278
}
276279

277-
// MARK: Mostly implemented message struct, missing file params
278-
public struct OutgoingMessage: Codable {
279-
public let content: String // The message contents (up to 2000 characters)
280-
public let tts: Bool?
281-
public let embeds: [Embed]?
282-
public let embed: Embed? // Embedded rich content, depreciated in favor of embeds
283-
public let allowed_mentions: AllowedMentions?
284-
public let message_reference: MessageReference?
285-
public let components: [MessageComponent]?
286-
public let sticker_ids: [Snowflake]?
287-
public let flags: Int?
288-
}
289-
290280
public enum MessageActivityType: Int, Codable {
291281
case join = 1
292282
case spectate = 2
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Nonce.swift
3+
//
4+
//
5+
// Created by Vincent Kwok on 19/3/24.
6+
//
7+
8+
import Foundation
9+
10+
public enum Nonce: Codable, Equatable {
11+
case string(String)
12+
case int(Int)
13+
14+
public static func == (lhs: Self, rhs: Self) -> Bool {
15+
lhs.value == rhs.value
16+
}
17+
18+
public var value: String {
19+
switch self {
20+
case .string(let val):
21+
return val
22+
case .int(let val):
23+
return String(val)
24+
}
25+
}
26+
27+
public func encode(to encoder: any Encoder) throws {
28+
var container = encoder.singleValueContainer()
29+
switch self {
30+
case .string(let val):
31+
try container.encode(val)
32+
case .int(let val):
33+
try container.encode(val)
34+
}
35+
}
36+
37+
public init(from decoder: any Decoder) throws {
38+
let container = try decoder.singleValueContainer()
39+
if let str = try? container.decode(String.self) {
40+
self = .string(str)
41+
} else {
42+
self = .int(try container.decode(Int.self))
43+
}
44+
}
45+
46+
public init() {
47+
self = .string(Snowflake(timestamp: Date()))
48+
}
49+
}

Sources/DiscordKitCore/Objects/Data/Snowflake.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,10 @@
88
import Foundation
99

1010
public typealias Snowflake = String
11+
12+
extension Snowflake {
13+
init(timestamp: Date = .init()) {
14+
let epoch = Int(timestamp.timeIntervalSince1970*1000) - DISCORD_EPOCH
15+
self.init(epoch << 22)
16+
}
17+
}

Sources/DiscordKitCore/Objects/REST/NewMessage.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ public struct NewMessage: Encodable {
2626
public let components: [Component]?
2727
public let sticker_ids: [Snowflake]?
2828
public let attachments: [NewAttachment]?
29+
public let nonce: Nonce?
2930
// file[n] // Handle file uploading later
3031
// attachments
3132
// let payload_json: Codable? // Handle this later
3233
public let flags: Int?
3334

34-
public init(content: String?, tts: Bool? = false, embeds: [Embed]? = nil, allowed_mentions: AllowedMentions? = nil, message_reference: MessageReference? = nil, components: [Component]? = nil, sticker_ids: [Snowflake]? = nil, attachments: [NewAttachment]? = nil, flags: Int? = nil) {
35+
public init(content: String?, nonce: Nonce = .init(), tts: Bool? = false, embeds: [Embed]? = nil, allowed_mentions: AllowedMentions? = nil, message_reference: MessageReference? = nil, components: [Component]? = nil, sticker_ids: [Snowflake]? = nil, attachments: [NewAttachment]? = nil, flags: Int? = nil) {
3536
self.content = content
3637
self.tts = tts
3738
self.embeds = embeds
@@ -41,6 +42,7 @@ public struct NewMessage: Encodable {
4142
self.sticker_ids = sticker_ids
4243
self.attachments = attachments
4344
self.flags = flags
45+
self.nonce = nonce
4446
}
4547

4648
enum CodingKeys: CodingKey {
@@ -53,6 +55,7 @@ public struct NewMessage: Encodable {
5355
case sticker_ids
5456
case attachments
5557
case flags
58+
case nonce
5659
}
5760

5861
public func encode(to encoder: Encoder) throws {
@@ -66,6 +69,7 @@ public struct NewMessage: Encodable {
6669
try container.encodeIfPresent(sticker_ids, forKey: .sticker_ids)
6770
try container.encodeIfPresent(attachments, forKey: .attachments)
6871
try container.encodeIfPresent(flags, forKey: .flags)
72+
try container.encodeIfPresent(nonce, forKey: .nonce)
6973

7074
// Same workaround to encode array of protocols
7175
if let components = components {

0 commit comments

Comments
 (0)