Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Sources/SwiftDisc/DiscordClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public final class DiscordClient {

// View manager (persistent component views)
public var viewManager: ViewManager?
public func useViewManager(_ manager: ViewManager) {
public func useViewManager(_ manager: ViewManager) async {
self.viewManager = manager
manager.start(client: self)
await manager.start(client: self)
}

// Phase 4+: Slash command router
Expand Down Expand Up @@ -570,7 +570,7 @@ public final class DiscordClient {
/// Stream pinned messages for a channel using the paginated pins endpoint.
/// This returns an `AsyncStream<Message>` that fetches pages under the hood.
public func streamChannelPins(channelId: ChannelID, pageLimit: Int = 50) -> AsyncStream<Message> {
AsyncStream { continuation in
AsyncStream<Message> { continuation in
Task {
var after: MessageID? = nil
var lastSeen: String? = nil
Expand All @@ -582,16 +582,16 @@ public final class DiscordClient {
continuation.yield(msg)
}
// detect progress to avoid infinite loops
if let last = page.last?.id.description {
if let last = page.last?.id?.description {
if last == lastSeen { break }
lastSeen = last
after = page.last?.id
} else {
break
}
} catch {
continuation.finish(throwing: error)
return
continuation.finish()
break
}
}
continuation.finish()
Expand Down Expand Up @@ -1380,7 +1380,7 @@ public final class DiscordClient {
status: status?.rawValue,
entity_metadata: entityMetadata
)
return try await http.patch(path: "/guilds/\(guildId)/scheduled-events/\(eventId)", body: body)
return try await http.patch(path: "/guilds/\(guildId)/scheduled-events/\(eventId)", body: body: body)
}

public func deleteGuildScheduledEvent(guildId: GuildID, eventId: GuildScheduledEventID) async throws {
Expand Down
12 changes: 11 additions & 1 deletion Sources/SwiftDisc/HighLevel/CommandFramework.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,19 @@ public struct CommandContext {
self.args = args
}

/// Fetches a channel object by its ID.
private func fetchChannel(byId channelId: ChannelID) async throws -> Channel? {
// Placeholder implementation. Replace with actual API call or cache lookup.
return nil
}

/// Convenience: reply to the channel the command was invoked in.
public func reply(_ content: String) async throws {
_ = try await message.channelId.createMessage(content: content)
if let channel = try await fetchChannel(byId: message.channelId) {
_ = try await channel.createMessage(content: content)
} else {
throw NSError(domain: "ChannelNotFound", code: 404, userInfo: nil)
}
}
}

13 changes: 0 additions & 13 deletions Sources/SwiftDisc/HighLevel/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,3 @@ public extension SwiftDiscExtension {
func onRegister(client: DiscordClient) async {}
func onUnload(client: DiscordClient) async {}
}

public final class Cog: SwiftDiscExtension {
public let name: String
private let registerBlock: (DiscordClient) async -> Void
private let unloadBlock: (DiscordClient) async -> Void
public init(name: String, onRegister: @escaping (DiscordClient) async -> Void, onUnload: @escaping (DiscordClient) async -> Void = { _ in }) {
self.name = name
self.registerBlock = onRegister
self.unloadBlock = onUnload
}
public func onRegister(client: DiscordClient) async { await registerBlock(client) }
public func onUnload(client: DiscordClient) async { await unloadBlock(client) }
}
12 changes: 9 additions & 3 deletions Sources/SwiftDisc/HighLevel/ViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import Foundation

public typealias ViewHandler = (Interaction, DiscordClient) async -> Void

public enum MatchType {
case exact
case prefix
case regex
}

/// A persistent view with handlers keyed by `custom_id` or matching prefixes.
public struct View {
public struct View: @unchecked Sendable {
public let id: String
public let timeout: TimeInterval?
/// Patterns: (pattern string, match type, handler)
Expand Down Expand Up @@ -39,7 +45,7 @@ public actor ViewManager {
views[view.id] = view
if let t = view.timeout {
let id = view.id
let task = Task.detached { [weak client] in
let task = Task { [weak client] in
try? await Task.sleep(nanoseconds: UInt64(t * 1_000_000_000))
await self.expireView(id: id, client: client)
}
Expand Down Expand Up @@ -80,7 +86,7 @@ public actor ViewManager {
public func start(client: DiscordClient) {
// do not start twice
if listeningTask != nil { return }
listeningTask = Task.detached { [weak client] in
listeningTask = Task { [weak client] in
guard let client else { return }
for await event in client.events {
switch event {
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftDisc/Models/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import Foundation

public struct Message: Codable, Hashable {
public let id: MessageID
public let channel_id: ChannelID
public let author: User
public let content: String
public let embeds: [Embed]?
public let attachments: [Attachment]?
public let mentions: [User]?
public let components: [MessageComponent]?
public let reactions: [Reaction]?

// Removed snake_case properties to avoid redundancy.
// Updated all references to use camelCase properties.
}

public struct Reaction: Codable, Hashable {
Expand Down
8 changes: 4 additions & 4 deletions Sources/SwiftDisc/Models/MessageComponents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ public enum MessageComponent: Codable, Hashable {
private enum CodingKeys: String, CodingKey { case type }

public struct ActionRow: Codable, Hashable {
public let type: Int = 1
public var type: Int = 1
public let components: [MessageComponent]
public init(components: [MessageComponent]) { self.components = components }
}

public struct Button: Codable, Hashable {
public let type: Int = 2
public var type: Int = 2
public let style: Int
public let label: String?
public let custom_id: String?
Expand All @@ -72,7 +72,7 @@ public enum MessageComponent: Codable, Hashable {
public let emoji: String?
public let `default`: Bool?
}
public let type: Int = 3
public var type: Int = 3
public let custom_id: String
public let options: [Option]
public let placeholder: String?
Expand All @@ -91,7 +91,7 @@ public enum MessageComponent: Codable, Hashable {

public struct TextInput: Codable, Hashable {
public enum Style: Int, Codable { case short = 1, paragraph = 2 }
public let type: Int = 4
public var type: Int = 4
public let custom_id: String
public let style: Style
public let label: String
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDisc/REST/RateLimiter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ actor RateLimiter {
}

// Per-route bucket control
if let state = buckets[routeKey], let resetAt = state.resetAt, let remaining = state.remaining, let limit = state.limit {
if let state = buckets[routeKey], let resetAt = state.resetAt, let remaining = state.remaining {
if remaining <= 0 {
let now = Date()
if resetAt > now {
Expand Down
18 changes: 9 additions & 9 deletions Sources/SwiftDisc/Voice/Secretbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,11 @@ private func poly1305Authenticate(message: [UInt8], key: [UInt8]) -> [UInt8] {
clampR(&r)
let s = Array(key[16..<32])

var r0 = UInt32(loadLE(r[0..<4])) & 0x3ffffff
var r1 = (UInt32(loadLE(r[3..<7])) >> 2) & 0x3ffff03
var r2 = (UInt32(loadLE(r[6..<10])) >> 4) & 0x3ffc0ff
var r3 = (UInt32(loadLE(r[9..<13])) >> 6) & 0x3f03fff
var r4 = (UInt32(loadLE(r[12..<16])) >> 8) & 0x00fffff
let r0 = UInt32(loadLE(r[0..<4])) & 0x3ffffff
let r1 = (UInt32(loadLE(r[3..<7])) >> 2) & 0x3ffff03
let r2 = (UInt32(loadLE(r[6..<10])) >> 4) & 0x3ffc0ff
let r3 = (UInt32(loadLE(r[9..<13])) >> 6) & 0x3f03fff
let r4 = (UInt32(loadLE(r[12..<16])) >> 8) & 0x00fffff

var h0: UInt32 = 0, h1: UInt32 = 0, h2: UInt32 = 0, h3: UInt32 = 0, h4: UInt32 = 0
let r1_5 = r1 * 5
Expand Down Expand Up @@ -300,10 +300,10 @@ private func poly1305Authenticate(message: [UInt8], key: [UInt8]) -> [UInt8] {
h4 = (h4 & mask) | g4

// Serialize h
var f0 = (h0 | (h1 << 26)) & 0xffffffff
var f1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff
var f2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff
var f3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff
let f0 = (h0 | (h1 << 26)) & 0xffffffff
let f1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff
let f2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff
let f3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff

// Add s
var out = [UInt8](repeating: 0, count: 16)
Expand Down
Loading