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

Commit 8eabe1b

Browse files
committed
Additional changes for CPU/memory fix
1 parent cbf54b1 commit 8eabe1b

File tree

3 files changed

+53
-50
lines changed

3 files changed

+53
-50
lines changed

Sources/Discord/Discord.swift

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

2525
import Foundation
26+
import Vapor
2627

2728
/// Represents a Discord bot.
2829
public class Bot {
@@ -85,13 +86,15 @@ public class Bot {
8586
var pendingApplicationCommands = [PendingAppCommand]()
8687
var pendingModals = [String: (Interaction) async -> Void]()
8788
var guildsCache = [Snowflake: Guild]()
88-
var msgCacheLock = NSLock()
8989
var isConnected = false
9090
var http: HTTPClient!
91-
var gw: Gateway?
92-
91+
var gw: Gateway!
9392
private var onceExecute: (() async -> Void)? = nil
9493

94+
private let msgCacheLock = NSLock()
95+
private let sema = DispatchSemaphore(value: 0)
96+
private let app = Vapor.Application()
97+
9598
/// Initializes the Discord bot.
9699
/// - Parameters:
97100
/// - token: The authentification token for the bot.
@@ -103,7 +106,8 @@ public class Bot {
103106
self.intents = intents
104107
self.sharding = sharding
105108
self.cacheManager = cacheManager
106-
http = .init(bot: self, token: token, version: version)
109+
gw = Gateway(bot: self, elg: app.eventLoopGroup)
110+
http = .init(bot: self, token: token, version: version, app: app)
107111
}
108112

109113
func cacheGuild(_ guild: Guild) {
@@ -141,16 +145,14 @@ public class Bot {
141145
/// - activity: The activity. Can be set to things such as "Listening to {value}", "Watching {value}", etc. Can be `nil` for no activity.
142146
/// - Note: Certain combinations are ignored by Discord. Some examples are setting the bots `status` to offline or setting a custom status.
143147
public func updatePresence(status: User.Status, activity: User.ActivityType?) {
144-
if let gw {
145-
var d: JSON = ["status": status.rawValue, "afk": false]
146-
147-
// Requires unix time in milliseconds
148-
d["since"] = status == .idle ? Date.now.timeIntervalSince1970 * 1000 : NIL
149-
d["activities"] = activity?.convert() ?? []
150-
151-
let payload: JSON = ["op": Opcode.presenceUpdate, "d": d]
152-
gw.sendFrame(payload)
153-
}
148+
var d: JSON = ["status": status.rawValue, "afk": false]
149+
150+
// Requires unix time in milliseconds
151+
d["since"] = status == .idle ? Date.now.timeIntervalSince1970 * 1000 : NIL
152+
d["activities"] = activity?.convert() ?? []
153+
154+
let payload: JSON = ["op": Opcode.presenceUpdate, "d": d]
155+
gw.sendFrame(payload)
154156
}
155157

156158
/// Retrieve all global application commands. If you need the commands for a specific guild, use ``Guild/applicationCommands()``.
@@ -336,19 +338,16 @@ public class Bot {
336338
}
337339

338340
/// Connect to Discord.
339-
/// - Attention: This method is blocking to maintain the connection to Discord.
340-
public func connect() async throws {
341-
if gw == nil {
342-
gw = Gateway(bot: self)
343-
try await gw!.startNewSession()
341+
public func connect() {
342+
if !isConnected {
343+
try! app.eventLoopGroup.any().makeFutureWithTask {
344+
try! await self.gw.startNewSession()
345+
}.wait()
344346
isConnected = true
345347
if let onceExecute {
346-
await onceExecute()
348+
Task { await onceExecute() }
347349
self.onceExecute = nil
348350
}
349-
while isConnected {
350-
await sleep(200)
351-
}
352351
}
353352
}
354353

@@ -367,6 +366,13 @@ public class Bot {
367366
guildsCache.removeAll()
368367
}
369368

369+
/// Disconnect from Discord and releases the block from ``run()``.
370+
public func close() {
371+
disconnect()
372+
app.shutdown()
373+
sema.signal()
374+
}
375+
370376
/// Create a guild. Your bot must be in less than 10 guilds to use this.
371377
/// - Parameters:
372378
/// - name: Name of the guild.
@@ -404,16 +410,12 @@ public class Bot {
404410
}
405411
}
406412

407-
/// Disconnects the bot from Discord, releases the block from ``connect()`` and clears the cache.
413+
/// Disconnect from Discord and clears the cache.
408414
public func disconnect() {
409-
if let gw {
415+
if isConnected {
410416
try! gw.ws.close(code: .normalClosure).wait()
411417
gw.resetGatewayValues()
412418
clearCache()
413-
try! gw.settings.loop.syncShutdownGracefully()
414-
self.gw = nil
415-
416-
// Must be last
417419
isConnected = false
418420
}
419421
}
@@ -572,9 +574,15 @@ public class Bot {
572574
return try await http.getWebhookWithToken(webhookId: webhookId, webhookToken: webhookToken)
573575
}
574576

577+
/// Connect to Discord and blocks the app from exiting.
578+
public func run() {
579+
connect()
580+
sema.wait()
581+
}
582+
575583
/// Block further execution until the ``EventListener/onReady(user:)`` event has been dispatched.
576584
public func waitUntilReady() async {
577-
while gw?.initialState?.dispatched != true {
585+
while gw.initialState?.dispatched != true {
578586
await sleep(150)
579587
}
580588
}

Sources/Discord/Gateway.swift

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ DEALINGS IN THE SOFTWARE.
2424

2525
import Foundation
2626
import WebSocketKit
27-
import Vapor
2827

2928
fileprivate struct ResumePayload {
3029

@@ -141,25 +140,25 @@ class Gateway {
141140

142141
var ws: WebSocket!
143142
var heartbeatTask: Task<(), Never>?
144-
var initialState: InitialState? = nil
143+
var initialState: InitialState?
145144

146145
private var bot: Bot
147146
private var wsResume: ResumePayload?
148147
private var gp: GatewayPayload?
149148
private var shards: Int?
150-
151149
private var heartbeatInterval = 0
152150
private var receivedReconnectRequest = false
153151

154-
let settings = (
152+
private let elg: EventLoopGroup
153+
private let settings = (
155154
port: 443,
156155
query: "v=10&encoding=json",
157-
config: WebSocketClient.Configuration(maxFrameSize: 1 << 20),
158-
loop: MultiThreadedEventLoopGroup(numberOfThreads: 2)
156+
config: WebSocketClient.Configuration(maxFrameSize: 1 << 20)
159157
)
160158

161-
init(bot: Bot) {
159+
init(bot: Bot, elg: EventLoopGroup) {
162160
self.bot = bot
161+
self.elg = elg
163162
}
164163

165164
/// Sends the RESUME payload for reconnects.
@@ -177,21 +176,19 @@ class Gateway {
177176
let resumeUrl = wsResume!.resumeGatewayURL!
178177
let cmps = extractURLComponents(URLComponents(string: resumeUrl)!)
179178

180-
let connection = WebSocket.connect(
179+
try! await WebSocket.connect(
181180
scheme: cmps.scheme,
182181
host: cmps.host,
183182
port: settings.port,
184183
query: settings.query,
185184
configuration: settings.config,
186-
on: settings.loop,
185+
on: elg,
187186
onUpgrade: { socket in
188187
self.websocketSetup(websocket: socket)
189188
Log.message("[Reconnect] connection successful - sending RESUME payload...")
190189
self.sendFrame(resumePayload)
191190
}
192-
)
193-
194-
try! await connection.get()
191+
).get()
195192
}
196193

197194
/// Binds all core functions of the websocket connection to the class.
@@ -248,20 +245,18 @@ class Gateway {
248245
resetGatewayValues()
249246
shards = results.shards
250247

251-
let connection = WebSocket.connect(
248+
try await WebSocket.connect(
252249
scheme: cmps.scheme,
253250
host: cmps.host,
254251
port: settings.port,
255252
query: settings.query,
256253
configuration: settings.config,
257-
on: settings.loop,
254+
on: elg,
258255
onUpgrade: { socket in
259256
self.websocketSetup(websocket: socket)
260257
Log.message("gateway connection established - receiver & onClose set")
261258
}
262-
)
263-
264-
try await connection.get()
259+
).get()
265260
}
266261

267262
/// Handles when the websocket is closed by Discord.

Sources/Discord/Http.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ class HTTPClient {
113113
let token: String
114114
let baseHeaders: HTTPHeaders
115115
let request: Request
116+
let app: Vapor.Application
116117

117118
var rateLimits = [String: RateLimit]()
118119

119-
let app = Vapor.Application()
120-
121-
init(bot: Bot, token: String, version: Version) {
120+
init(bot: Bot, token: String, version: Version, app: Vapor.Application) {
122121
self.bot = bot
123122
self.token = token
123+
self.app = app
124124
self.request = Request(application: app, on: app.eventLoopGroup.any())
125125

126126
baseHeaders = [

0 commit comments

Comments
 (0)