Skip to content
This repository was archived by the owner on Jan 3, 2024. It is now read-only.

Commit 525a72c

Browse files
committed
Fix messages not being removed from cache
This additionally implements the same fix for components. Although it did not affect components, it's better for all items that used `Timer` to swap to the new method
1 parent 89b08a8 commit 525a72c

File tree

4 files changed

+38
-30
lines changed

4 files changed

+38
-30
lines changed

Sources/Discord/Discord.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public class Bot {
9191
var gw: Gateway!
9292
private var onceExecute: (() async -> Void)? = nil
9393

94+
let loop: EventLoop
9495
private let msgCacheLock = NSLock()
9596
private let sema = DispatchSemaphore(value: 0)
9697
private let app = Vapor.Application()
@@ -106,6 +107,7 @@ public class Bot {
106107
self.intents = intents
107108
self.sharding = sharding
108109
self.cacheManager = cacheManager
110+
loop = app.eventLoopGroup.any()
109111
gw = Gateway(bot: self, elg: app.eventLoopGroup)
110112
http = .init(bot: self, token: token, version: version, app: app)
111113
}
@@ -139,7 +141,7 @@ public class Bot {
139141

140142
func removeCachedMessage(_ messageId: Snowflake) {
141143
if let message = cachedMessages.first(where: { $0.id == messageId }) {
142-
message.cacheExpireTimer?.invalidate()
144+
message.cacheExpireScheduler?.cancel()
143145
cachedMessages.remove(message)
144146
}
145147
}
@@ -521,7 +523,7 @@ public class Bot {
521523
/// - Returns: The message matching the provided ID, or `nil` if not found.
522524
public func getMessage(_ id: Snowflake) -> Message? {
523525
if let msg = cachedMessages.first(where: { $0.id == id }) {
524-
msg.setExpires()
526+
msg.setScheduler()
525527
return msg
526528
}
527529
return nil

Sources/Discord/Gateway.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,9 @@ class Gateway {
467467
}
468468
case .messageComponent:
469469
if let cachedMsg = interaction.bot!.getMessage(interaction.message!.id) {
470-
// Reset the onTimeout timer. With each interaction this is reset because I don't want the
470+
// Reset the onTimeout scheduler. With each interaction this is reset because I don't want the
471471
// components to be disabled (by default) when components are in active use
472-
cachedMsg.ui?.startOnTimeoutTimer()
472+
cachedMsg.ui?.startOnTimeoutScheduler()
473473

474474
await cachedMsg.ui?.onInteraction(interaction)
475475
}
@@ -984,8 +984,8 @@ class Gateway {
984984
let guildId = Conversions.snowflakeToOptionalUInt(data["guild_id"])
985985

986986
if let message = bot.getMessage(messageId) {
987-
// Before the message is removed from the cache, invalidate the UI onTimeout timer
988-
message.ui?.timer?.invalidate()
987+
// Before the message is removed from the cache, cancel the UI onTimeout scheduler
988+
message.ui?.scheduler?.cancel()
989989

990990
bot.removeCachedMessage(message.id)
991991
dispatch({ await $0.onMessageDelete(message: message) })

Sources/Discord/Models/Components.swift

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE.
2323
*/
2424

2525
import Foundation
26+
import NIOCore
27+
import NIOPosix
2628

2729
/// Represents a components type.
2830
public enum ComponentType : Int {
@@ -69,12 +71,17 @@ public class UI {
6971
/// The message the UI is attached to.
7072
public private(set) var attachedMessage: Message? = nil
7173

72-
var timer: Timer? = nil
74+
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
75+
var scheduler: Scheduled<()>? = nil
7376

7477
/// Initializes a UI.
7578
/// - Parameter timeout: The amount of time in seconds for when the UI times out and the `onTimeout` closure is called.
7679
public init(timeout: TimeInterval = 120) {
77-
self.timeout = timeout < 0 ? 120 : timeout
80+
self.timeout = timeout < 0 ? 0 : timeout
81+
}
82+
83+
deinit {
84+
try? elg.syncShutdownGracefully()
7885
}
7986

8087
/// Add an item to the UI.
@@ -151,15 +158,11 @@ public class UI {
151158
return self
152159
}
153160

154-
func startOnTimeoutTimer() {
155-
timer?.invalidate()
156-
DispatchQueue.main.async {
157-
self.timer = .scheduledTimer(withTimeInterval: self.timeout, repeats: false, block: { _ in
158-
Task {
159-
await self.onTimeout(self.attachedMessage)
160-
}
161-
})
162-
}
161+
func startOnTimeoutScheduler() {
162+
scheduler?.cancel()
163+
scheduler = elg.any().scheduleTask(in: .seconds(Int64(timeout)), {
164+
Task { await self.onTimeout(self.attachedMessage) }
165+
})
163166
}
164167

165168
func convert() throws -> [JSON] {
@@ -195,7 +198,7 @@ public class UI {
195198
if let ui, let cachedMessage = message.bot!.getMessage(message.id) {
196199
cachedMessage.ui = ui
197200
ui.attachedMessage = cachedMessage
198-
ui.startOnTimeoutTimer()
201+
ui.startOnTimeoutScheduler()
199202
}
200203
}
201204

Sources/Discord/Models/Message.swift

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE.
2323
*/
2424

2525
import Foundation
26+
import NIOCore
2627

2728
/// Represents a Discord message.
2829
public class Message : Object, Hashable, Updateable {
@@ -209,13 +210,15 @@ public class Message : Object, Hashable, Updateable {
209210
/// Your bot instance.
210211
public weak private(set) var bot: Bot?
211212

212-
static var cacheExpire: Date { Calendar.current.date(byAdding: .hour, value: 3, to: .now)! }
213-
var cacheExpireTimer: Timer? = nil
213+
var guildId: Snowflake?
214+
215+
var cacheExpireScheduler: Scheduled<()>? = nil
216+
var expires: Date! // initialized in setScheduler()
217+
static let expireAfter = 5
218+
static var cacheExpire: Date { Calendar.current.date(byAdding: .hour, value: Message.expireAfter, to: .now)! }
214219

215220
let channelId: Snowflake
216-
var guildId: Snowflake?
217221
let mentionRoleStrings: [String]
218-
var expires: Date
219222
let temp: JSON
220223

221224
init(bot: Bot, messageData: JSON) {
@@ -295,8 +298,7 @@ public class Message : Object, Hashable, Updateable {
295298
}
296299
}
297300

298-
expires = Message.cacheExpire
299-
setExpires()
301+
setScheduler()
300302

301303
// This was moved to the end because `self` cannot be used before all stored proprties have been initalized.
302304
if let reactionObjs = messageData["reactions"] as? [JSON] {
@@ -479,13 +481,14 @@ public class Message : Object, Hashable, Updateable {
479481
try await bot!.http.crosspostMessage(channelId: channel.id, messageId: id)
480482
}
481483

482-
func setExpires() {
484+
func setScheduler() {
485+
// Set/reset the expiration date. This method is called during this init() or
486+
// when a message is retrieved via Bot.getMessage()
483487
expires = Message.cacheExpire
484-
cacheExpireTimer?.invalidate()
485-
DispatchQueue.main.async {
486-
self.cacheExpireTimer = .scheduledTimer(withTimeInterval: self.expires.timeIntervalSince(.now), repeats: false, block: { [self] _ in
487-
bot!.removeCachedMessage(id)
488-
})
488+
489+
cacheExpireScheduler?.cancel()
490+
cacheExpireScheduler = bot!.loop.scheduleTask(in: .hours(Int64(Message.expireAfter))) {
491+
self.bot!.removeCachedMessage(self.id)
489492
}
490493
}
491494

0 commit comments

Comments
 (0)