Skip to content

Commit 101eaeb

Browse files
feat(user): update for new user ready payload format
1 parent dc16b00 commit 101eaeb

File tree

10 files changed

+97
-51
lines changed

10 files changed

+97
-51
lines changed

Sources/DiscordKit/Gateway/DiscordGateway.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public class DiscordGateway: ObservableObject {
200200
var modifiedGuild = updatedGuild
201201

202202
// ``GatewayEvent.guildUpdate`` events are missing data that is only present in the initial ``GatewayEvent.ready`` event, so we need to copy those properties over manually.
203-
modifiedGuild.joined_at = existingGuild.joined_at
203+
/*modifiedGuild.joined_at = existingGuild.joined_at
204204
modifiedGuild.large = existingGuild.large
205205
modifiedGuild.unavailable = existingGuild.unavailable
206206
modifiedGuild.member_count = existingGuild.member_count
@@ -210,9 +210,9 @@ public class DiscordGateway: ObservableObject {
210210
modifiedGuild.threads = existingGuild.threads
211211
modifiedGuild.presences = existingGuild.presences
212212
modifiedGuild.stage_instances = existingGuild.stage_instances
213-
modifiedGuild.guild_scheduled_events = existingGuild.guild_scheduled_events
213+
modifiedGuild.guild_scheduled_events = existingGuild.guild_scheduled_events*/
214214

215-
cache.appendOrReplace(modifiedGuild)
215+
// cache.appendOrReplace(modifiedGuild)
216216
}
217217

218218
private func handleProtoUpdate(proto: String) {
@@ -260,14 +260,14 @@ public class DiscordGateway: ObservableObject {
260260
}
261261

262262
// MARK: Guild events
263-
case .guildCreate(let guild): cache.appendOrReplace(guild)
263+
// case .guildCreate(let guild): cache.appendOrReplace(guild)
264264

265265
case .guildDelete(let guild): cache.remove(guild)
266266

267267
case .guildUpdate(let guild): handleGuildUpdate(guild)
268268

269269
// MARK: User updates
270-
case .userUpdate(let currentUser): cache.user = currentUser
270+
case .userUpdate(let currentUser): cache.replace(currentUser)
271271

272272
case .settingsProtoUpdate(let protoUpdate):
273273
guard !protoUpdate.partial else {

Sources/DiscordKit/Gateway/GatewayCachedState.swift

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ public class CachedState: ObservableObject {
1515
/// Dictionary of guilds the user is in
1616
///
1717
/// > The guild's ID is its key
18-
public private(set) var guilds: [Snowflake: Guild] = [:]
18+
@Published public private(set) var guilds: [Snowflake: PreloadedGuild] = [:]
19+
20+
@Published public private(set) var members: [Snowflake: Member] = [:]
1921

2022
/// DM channels the user is in
21-
public var dms: [Channel] = []
23+
@Published public private(set) var dms: [Channel] = []
2224

2325
/// Cached object of current user
24-
public var user: CurrentUser?
26+
@Published public private(set) var user: CurrentUser?
2527

2628
/// Cached users, initially populated from `READY` event and might
2729
/// grow over time
28-
public private(set) var users: [Snowflake: User] = [:]
30+
@Published public private(set) var users: [Snowflake: User] = [:]
2931

3032
/// Populates the cache using the provided event.
3133
/// - Parameter event: An incoming Gateway "ready" event.
@@ -34,13 +36,17 @@ public class CachedState: ObservableObject {
3436
dms = event.private_channels
3537
user = event.user
3638
event.users.forEach(appendOrReplace(_:))
39+
event.merged_members.enumerated().forEach { (idx, guildMembers) in
40+
members[event.guilds[idx].id] = guildMembers.first(where: { $0.user_id == event.user.id })
41+
}
42+
print(members)
3743
}
3844

39-
// MARK: Guilds
45+
// MARK: - Guilds
4046

4147
/// Updates or appends the provided guild.
4248
/// - Parameter guild: The guild you want to update or append to the cache.
43-
func appendOrReplace(_ guild: Guild) {
49+
func appendOrReplace(_ guild: PreloadedGuild) {
4450
guilds.updateValue(guild, forKey: guild.id)
4551
}
4652

@@ -50,7 +56,7 @@ public class CachedState: ObservableObject {
5056
guilds.removeValue(forKey: guild.id)
5157
}
5258

53-
// MARK: Channels
59+
// MARK: - Channels
5460

5561
/// Appends the provided channel to the appropriate cached guild.
5662
/// - Parameter channel: The channel to append.
@@ -59,7 +65,7 @@ public class CachedState: ObservableObject {
5965
return
6066
}
6167

62-
guilds[identifier]?.channels?.append(channel)
68+
// guilds[identifier]?.channels?.append(channel)
6369
}
6470

6571
/// Removes the provided channel from the appropriate cached guild.
@@ -69,13 +75,15 @@ public class CachedState: ObservableObject {
6975
return
7076
}
7177

72-
guilds[identifier]?.channels?.removeAll(matchingIdentifierFor: channel)
78+
// guilds[
79+
80+
// guilds[identifier]?.channels?.removeAll(matchingIdentifierFor: channel)
7381
}
7482

7583
/// Replaces the first channel with an identifier that matches the provided channel's identifier..
7684
/// - Parameter channel: The channel to replace
7785
func replace(_ channel: Channel) {
78-
guard
86+
/*guard
7987
let guildID = channel.guild_id,
8088
let channelIndex = guilds[guildID]?
8189
.channels?
@@ -84,10 +92,10 @@ public class CachedState: ObservableObject {
8492
return
8593
}
8694

87-
guilds[guildID]?.channels?[channelIndex] = channel
95+
guilds[guildID]?.channels?[channelIndex] = channel*/
8896
}
8997

90-
// MARK: Messages
98+
// MARK: - Messages
9199

92100
/// Appends or replaces the given message within the appropriate channel.
93101
/// - Parameter message: The message to append.
@@ -97,11 +105,16 @@ public class CachedState: ObservableObject {
97105
}
98106
}
99107

100-
// MARK: Users
108+
// MARK: - Users
101109

102110
/// Appends or replaces the provided user in the cache.
103111
/// - Parameter user: The user to cache.
104112
func appendOrReplace(_ user: User) {
105113
users.updateValue(user, forKey: user.id)
106114
}
115+
116+
/// Replaces the current user with the provided one
117+
func replace(_ user: CurrentUser) {
118+
self.user = user
119+
}
107120
}

Sources/DiscordKitCore/DiscordKitConfig.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ public struct GatewayConnProperties: OutgoingGatewayData {
4747
device: String? = nil,
4848
release_channel: String? = nil,
4949
client_version: String? = nil,
50-
os_version: String? = nil,
51-
os_arch: String? = nil,
50+
os_version: String? = "22.4.0",
51+
os_arch: String? = "arm64",
5252
system_locale: String? = nil,
5353
client_build_number: Int? = nil
5454
) {
@@ -250,8 +250,8 @@ public struct DiscordKitConfig {
250250
/// Currently the only missing piece of emulating the official
251251
/// desktop client completely is ETF packing/unpacking.
252252
public static let clientParity = ClientParityVersion(
253-
version: "0.0.283",
254-
buildNumber: 115689,
253+
version: "0.0.296",
254+
buildNumber: 197575,
255255
releaseCh: .canary,
256256
electronVersion: "13.6.6"
257257
)

Sources/DiscordKitCore/Gateway/GatewayIdentify.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,24 @@ public extension RobustWebSocket {
1919
/// not present in the keychain
2020
internal func getIdentify() -> GatewayIdentify? {
2121
return GatewayIdentify(
22-
token: self.token,
22+
token: token,
2323
properties: DiscordKitConfig.default.properties,
2424
compress: false,
2525
large_threshold: nil,
2626
shard: nil,
2727
presence: GatewayPresenceUpdate(since: 0, activities: [], status: .online, afk: false),
2828
client_state: DiscordKitConfig.default.isBot ? nil : ClientState( // Just a dummy client_state
29-
guild_hashes: GuildHashes(),
29+
api_code_version: 0,
30+
guild_versions: .init(),
3031
highest_last_message_id: "0",
32+
initial_guild_id: nil,
33+
private_channels_version: "0",
3134
read_state_version: 0,
3235
user_guild_settings_version: -1,
3336
user_settings_version: -1
3437
),
35-
capabilities: DiscordKitConfig.default.isBot ? nil : 0b1111111101, // TODO: Reverse engineer this
36-
intents: DiscordKitConfig.default.intents
38+
capabilities: DiscordKitConfig.default.isBot ? nil : 8189, // TODO: Reverse engineer this
39+
intents: DiscordKitConfig.default.isBot ? DiscordKitConfig.default.intents : nil
3740
)
3841
}
3942

Sources/DiscordKitCore/Gateway/RobustWebSocket.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,28 +163,31 @@ public class RobustWebSocket: NSObject {
163163
}
164164

165165
private func attachSockReceiveListener() {
166-
socket.receive { [weak self] result in
166+
socket.receive { [unowned self] result in
167167
// print(result)
168168
switch result {
169169
case .success(let message):
170170
do {
171171
switch message {
172172
case .data(let data):
173-
if let decompressed = self?.decompressor.push_data(data) {
174-
try self?.handleMessage(with: decompressed)
175-
} else { Self.log.trace("Decompression did not return any result - compressed packet is not complete") }
176-
case .string(let str): try self?.handleMessage(with: str)
173+
if let decompressed = decompressor.push_data(data) {
174+
// print(decompressed)
175+
try handleMessage(with: decompressed)
176+
} else {
177+
Self.log.trace("Decompression did not return any result - compressed packet is not complete")
178+
}
179+
case .string(let str): try handleMessage(with: str)
177180
@unknown default: Self.log.warning("Unknown sock message case!")
178181
}
179182
} catch {
180183
// TODO: Add handler for decoding errors
181184
Self.log.warning("Error decoding message", metadata: ["error": "\(error)"])
182185
}
183-
self?.attachSockReceiveListener()
186+
attachSockReceiveListener()
184187
case .failure(let error):
185188
// If an error is encountered here, the connection is probably broken
186189
Self.log.error("Receive error", metadata: ["error": "\(error.localizedDescription)"])
187-
self?.forceClose()
190+
forceClose()
188191
}
189192
}
190193
}
@@ -343,6 +346,11 @@ public class RobustWebSocket: NSObject {
343346
session = URLSession(configuration: .default, delegate: self, delegateQueue: queue)
344347
connect()
345348
}
349+
350+
// Gracefully disconnect when deinitialised
351+
deinit {
352+
close(code: .normalClosure)
353+
}
346354
}
347355

348356
public typealias ReconnectDelayClosure = (URLSessionWebSocketTask.CloseCode?, Int) -> TimeInterval?

Sources/DiscordKitCore/Objects/Data/Guild.swift

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ public struct Guild: GatewayData, Equatable, Identifiable {
5858
self.verification_level = verification_level
5959
self.default_message_notifications = default_message_notifications
6060
self.explicit_content_filter = explicit_content_filter
61-
self.roles = roles
62-
self.emojis = emojis
6361
self.features = features
6462
self.mfa_level = mfa_level
6563
self.application_id = application_id
@@ -71,9 +69,6 @@ public struct Guild: GatewayData, Equatable, Identifiable {
7169
self.unavailable = unavailable
7270
self.member_count = member_count
7371
self.voice_states = voice_states
74-
self.members = members
75-
self.channels = channels
76-
self.threads = threads
7772
self.presences = presences
7873
self.max_presences = max_presences
7974
self.max_members = max_members
@@ -90,13 +85,12 @@ public struct Guild: GatewayData, Equatable, Identifiable {
9085
self.welcome_screen = welcome_screen
9186
self.nsfw_level = nsfw_level
9287
self.stage_instances = stage_instances
93-
self.stickers = stickers
94-
self.guild_scheduled_events = guild_scheduled_events
88+
self.guild_scheduled_events = guild_scheduled_events
9589
self.premium_progress_bar_enabled = premium_progress_bar_enabled
9690
}
9791

9892
public static func == (lhs: Guild, rhs: Guild) -> Bool {
99-
lhs.id == rhs.id && lhs.name == rhs.name && lhs.channels == rhs.channels
93+
lhs.id == rhs.id && lhs.name == rhs.name
10094
}
10195

10296
public let id: Snowflake
@@ -116,8 +110,6 @@ public struct Guild: GatewayData, Equatable, Identifiable {
116110
public let verification_level: VerificationLevel
117111
public let default_message_notifications: MessageNotifLevel
118112
public let explicit_content_filter: ExplicitContentFilterLevel
119-
public let roles: [DecodableThrowable<Role>]
120-
public let emojis: [DecodableThrowable<Emoji>]
121113
public let features: [DecodableThrowable<GuildFeature>]
122114
public let mfa_level: MFALevel
123115
public let application_id: Snowflake? // For bot-created guilds
@@ -129,9 +121,6 @@ public struct Guild: GatewayData, Equatable, Identifiable {
129121
public var unavailable: Bool? // If guild is unavailable due to an outage
130122
public var member_count: Int?
131123
public var voice_states: [VoiceState]?
132-
public var members: [Member]?
133-
public var channels: [Channel]?
134-
public var threads: [Channel]?
135124
public var presences: [PresenceUpdate]?
136125
public let max_presences: Int? // null is always returned, apart from the largest of guilds
137126
public let max_members: Int?
@@ -148,11 +137,35 @@ public struct Guild: GatewayData, Equatable, Identifiable {
148137
public let welcome_screen: GuildWelcomeScreen?
149138
public let nsfw_level: NSFWLevel
150139
public var stage_instances: [StageInstance]?
151-
public let stickers: [Sticker]?
152140
public var guild_scheduled_events: [GuildScheduledEvent]?
153141
public let premium_progress_bar_enabled: Bool
154142
}
155143

144+
/// Guild received in initial ready payload, contains more info than what can be found in ``Guild``
145+
///
146+
/// > Not all fields have been added below, only the required ones
147+
public struct PreloadedGuild: GatewayData, Identifiable, Equatable {
148+
public static func == (lhs: PreloadedGuild, rhs: PreloadedGuild) -> Bool {
149+
lhs.properties == rhs.properties && lhs.id == rhs.id
150+
}
151+
152+
public let version: Int
153+
public let channels: [Channel]
154+
public let emojis: [DecodableThrowable<Emoji>]
155+
public let id: Snowflake
156+
public let joined_at: Date
157+
public let large: Bool
158+
public let lazy: Bool
159+
public let member_count: Int
160+
161+
/// Number of "boosts" the server has
162+
public let premium_subscription_count: Int
163+
public let properties: Guild
164+
public let roles: [DecodableThrowable<Role>]
165+
public let stickers: [Sticker]
166+
// public let threads:
167+
}
168+
156169
// Partial Guild, returned when listing guilds
157170
public struct PartialGuild: Codable, GatewayData {
158171
public let id: Snowflake

Sources/DiscordKitCore/Objects/Data/Member.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ public struct Member: Codable, GatewayData {
2020
public let permissions: String? // Total permissions of the member in the channel, including overwrites, returned when in the interaction object
2121
public let communication_disabled_until: Date? // When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out
2222
public let guild_id: Snowflake?
23+
public let user_id: Snowflake? // Only present in merged_members in READY payload!
2324
}

Sources/DiscordKitCore/Objects/Gateway/DataStructs.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,13 @@ public struct SubscribeGuildEvts: OutgoingGatewayData {
112112
///
113113
/// > Warning: This should only be sent in identify payloads for user accounts. Bot accounts don't need this!
114114
struct ClientState: OutgoingGatewayData {
115-
let guild_hashes: GuildHashes
115+
struct GuildVersion: OutgoingGatewayData { }
116+
117+
let api_code_version: Int
118+
let guild_versions: GuildVersion
116119
let highest_last_message_id: Snowflake
120+
let initial_guild_id: Snowflake?
121+
let private_channels_version: String
117122
let read_state_version: Int
118123
let user_guild_settings_version: Int
119124
let user_settings_version: Int

Sources/DiscordKitCore/Objects/Gateway/Event/ReadyEvt.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ public struct ReadyEvt: Decodable, GatewayData {
1313
public let v: Int
1414
public let user: CurrentUser
1515
public let users: [User]
16-
public let guilds: [Guild]
16+
public let guilds: [PreloadedGuild]
1717
public let session_id: String
1818
public let user_settings: UserSettings? // Depreciated, no longer sent
1919
/// Protobuf of user settings
2020
public let user_settings_proto: String
2121
/// DMs for this user
2222
public let private_channels: [Channel]
2323

24+
public let merged_members: [[Member]]
25+
2426
/// The user's unreads
2527
///
2628
/// > An implementation for unreads is still WIP in Swiftcord

Sources/DiscordKitCore/Objects/Gateway/GatewayIO.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,12 @@ public struct GatewayIncoming: Decodable {
213213
// Cue the long switch case to parse every single event
214214
switch type {
215215
case .ready:
216-
if let userReady = try? values.decode(ReadyEvt.self, forKey: .data) {
216+
/*if let userReady = try? values.decode(ReadyEvt.self, forKey: .data) {
217217
data = .userReady(userReady)
218218
} else {
219219
data = .botReady(try values.decode(BotReadyEvt.self, forKey: .data))
220-
}
220+
}*/
221+
data = .userReady(try values.decode(ReadyEvt.self, forKey: .data))
221222
case .readySupplemental: data = .readySupplemental(try values.decode(ReadySuppEvt.self, forKey: .data))
222223
case .resumed: data = .resumed
223224

0 commit comments

Comments
 (0)