Skip to content

Commit

Permalink
a bunch of minor refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
MahdiBM committed Feb 4, 2024
1 parent 2cf1f90 commit 39230ff
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 18 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -171,7 +171,7 @@ In [Discord developer portal](https://discord.com/developers/applications):

`DiscordBM` comes with full support for all kinds of "interactions" such as slash commands, modals, autocomplete etc... and gives you full control over how you want to use them using type-safe APIs.
> You can see Penny as an example of using all kinds of commands in production.
Penny registers the commands [here](https://github.com/vapor/penny-bot/blob/main/CODE/Sources/PennyBOT/CommandsManager.swift) and responds to them [here](https://github.com/vapor/penny-bot/blob/main/CODE/Sources/PennyBOT/Handlers/InteractionHandler.swift).
Penny registers the commands [here](https://github.com/vapor/penny-bot/blob/main/Sources/Penny/CommandsManager.swift) and responds to them [here](https://github.com/vapor/penny-bot/blob/main/Sources/Penny/Handlers/InteractionHandler.swift).

In this example you'll only make 2 simple slash commands, so you can get started:

Expand Down Expand Up @@ -397,6 +397,10 @@ enum LinkSubCommand: String, CaseIterable {
* `requireRoleSelect() throws -> SelectMenu`
* `requireMentionableSelect() throws -> SelectMenu`
* `requireChannelSelect() throws -> ChannelSelectMenu`
* `Interaction.Data` has:
* `requireApplicationCommand() throws -> ApplicationCommand`
* `requireMessageComponent() throws -> MessageComponent`
* `requireModalSubmit() throws -> ModalSubmit`
* Swift's `Optional` has a `requireValue() throws` function overload (only in `DiscordBM`).

</details>
Expand Down
7 changes: 4 additions & 3 deletions Sources/DiscordHTTP/Endpoints/Endpoint.swift
Expand Up @@ -7,16 +7,17 @@ public protocol Endpoint: Sendable, CustomStringConvertible {
var httpMethod: HTTPMethod { get }
/// Interaction endpoints don't count against the global rate limit.
/// Even if the global rate-limit is exceeded, you can still respond to interactions.
/// So this is used for interaction endpoints.
var countsAgainstGlobalRateLimit: Bool { get }
/// Some endpoints don't require an authorization header because the endpoint url itself
/// contains some kind of authorization token. Like some of the webhook endpoints.
/// Some endpoints don't require an authorization header, sometimes because the endpoint url
/// itself contains some kind of authorization token. Like some of the webhook endpoints.
var requiresAuthorizationHeader: Bool { get }
/// Path parameters.
var parameters: [String] { get }
var id: Int { get }
}

/// Just to switch between the 2 endpoint types.
/// Just to switch between the 3 endpoint types.
public enum AnyEndpoint: Endpoint {
case api(APIEndpoint)
case cdn(CDNEndpoint)
Expand Down
4 changes: 2 additions & 2 deletions Sources/DiscordHTTP/Endpoints/LooseEndpoint.swift
Expand Up @@ -31,12 +31,12 @@ public struct LooseEndpoint: Endpoint, Hashable {
}

public func hash(into hasher: inout Hasher) {
/// Only `url` is dynamic, so no need to hash other stuff.
hasher.combine(url)
hasher.combine(httpMethod.rawValue)
}

public var description: String {
#"LooseEndpoint(url: "\#(url)", httpMethod: \#(httpMethod))"#
#"LooseEndpoint(url: "\#(url)")"#
}

public init(url: String) {
Expand Down
6 changes: 3 additions & 3 deletions Sources/DiscordHTTP/HTTPRateLimiter.swift
Expand Up @@ -37,7 +37,7 @@ actor HTTPRateLimiter {
self.reset = reset
}

func shouldRequest() -> ShouldRequestResponse {
func shouldRequest() -> ShouldRequest {
if remaining > 0 {
return .true
} else {
Expand Down Expand Up @@ -146,7 +146,7 @@ actor HTTPRateLimiter {
}

@usableFromInline
enum ShouldRequestResponse: Sendable {
enum ShouldRequest: Sendable {
case `true`
case `false`
/// Need to wait some seconds if you want to make the request
Expand All @@ -159,7 +159,7 @@ actor HTTPRateLimiter {
/// global rate-limit will be less than the max amount and might not allow you
/// to make too many requests per second, when it should.
@usableFromInline
func shouldRequest(to endpoint: AnyEndpoint) -> ShouldRequestResponse {
func shouldRequest(to endpoint: AnyEndpoint) -> ShouldRequest {
guard minutelyInvalidRequestsLimitAllows() else { return .false }
if endpoint.countsAgainstGlobalRateLimit {
guard globalRateLimitAllows() else { return .false }
Expand Down
14 changes: 7 additions & 7 deletions Sources/DiscordModels/Protocols/MultipartEncodable.swift
Expand Up @@ -11,7 +11,7 @@ public protocol MultipartEncodable: Encodable {
/// By default, DiscordBM encodes the `files` as one field,
/// and the rest of the payload as a `payload_json` field, which is what Discord asks.
/// However, very few endpoints don't accept that approach.
/// Payloads that set this to `true` shouldn't specify `CodingKeys`
/// Payloads that set this to `true` mustn't specify `CodingKeys`
/// to exclude the `files` from `Codable`.
static var rawEncodable: Bool { get }
}
Expand Down Expand Up @@ -90,22 +90,22 @@ public struct RawFile: Sendable, Encodable, MultipartPartConvertible {
}

public var multipart: MultipartPart? {
var part = MultipartPart(headers: [:], body: .init(self.data.readableBytesView))
var part = MultipartPart(headers: [:], body: self.data)
if let type {
part.headers.add(name: "Content-Type", value: type)
}
part.headers.add(name: "Content-Disposition", value: #"form-data; filename="\#(self.filename)""#)
part.headers.add(
name: "Content-Disposition",
value: #"form-data; filename="\#(self.filename)""#
)
return part
}

public init? (multipart: MultipartPart) {
if let header = multipart.headers.first(name: "Content-Disposition") {
let parts = header.split(separator: ";").compactMap {
part -> (key: Substring, value: Substring)? in
var part = part
if part.first == " " {
part.removeFirst()
}
let part = part.trimmingPrefix(" ")
let split = part.split(separator: "=")
guard split.count == 2 else { return nil }
return (split[0], split[1])
Expand Down
6 changes: 5 additions & 1 deletion Sources/DiscordModels/Types/Interaction.swift
Expand Up @@ -269,6 +269,7 @@ public struct Interaction: Sendable, Codable {
case messageComponent(MessageComponent)
case modalSubmit(ModalSubmit)

/// Requires an `ApplicationCommand` value or throws `Interaction.Error`.
public func requireApplicationCommand() throws -> ApplicationCommand {
switch self {
case let .applicationCommand(applicationCommand):
Expand All @@ -278,6 +279,7 @@ public struct Interaction: Sendable, Codable {
}
}

/// Requires a `MessageComponent` value or throws `Interaction.Error`.
public func requireMessageComponent() throws -> MessageComponent {
switch self {
case let .messageComponent(messageComponent):
Expand All @@ -287,6 +289,7 @@ public struct Interaction: Sendable, Codable {
}
}

/// Requires a `ModalSubmit` value or throws `Interaction.Error`.
public func requireModalSubmit() throws -> ModalSubmit {
switch self {
case let .modalSubmit(modalSubmit):
Expand Down Expand Up @@ -360,7 +363,8 @@ public struct Interaction: Sendable, Codable {
)
case .ping:
self.data = nil
case .__undocumented: self.data = nil
case .__undocumented:
self.data = nil
}
self.guild_id = try container.decodeIfPresent(GuildSnowflake.self, forKey: .guild_id)
self.channel_id = try container.decodeIfPresent(
Expand Down
2 changes: 1 addition & 1 deletion Tests/DiscordBMTests/HTTPRateLimiter.swift
Expand Up @@ -146,7 +146,7 @@ class HTTPRateLimiterTests: XCTestCase {
}
}

extension HTTPRateLimiter.ShouldRequestResponse: Equatable {
extension HTTPRateLimiter.ShouldRequest: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
if case .true = lhs, case .true = rhs {
return true
Expand Down

0 comments on commit 39230ff

Please sign in to comment.