Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v10.0.0 #81

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7f00441
Added multiple message send feature
TellowKrinkle Jul 28, 2018
02cd0d3
Remove unnecessary parentheses
TellowKrinkle Jul 30, 2018
0fc784c
Merge pull request #71 from tellowkrinkle/MultiSend
nuclearace Aug 7, 2018
0f41e21
fix linux build
nuclearace Aug 23, 2018
f4ddb84
Merge pull request #72 from nuclearace/fix-linux
nuclearace Aug 23, 2018
74d6c1e
Merge branch 'master' into development
nuclearace Aug 23, 2018
510c551
Hopefully fix DiscordGatewayPayloadData.dataFromDictionary on Swift 4…
TellowKrinkle Oct 6, 2018
f03ab07
Merge pull request #74 from tellowkrinkle/development
nuclearace Oct 6, 2018
e7a04e9
Fix calls to crypto_secretbox_easy
TellowKrinkle Feb 4, 2019
bebe252
Don't `&` const pointers
TellowKrinkle Feb 4, 2019
691787a
Merge pull request #76 from tellowkrinkle/FixSecretboxEasy
nuclearace Feb 4, 2019
e8f223e
Add message reaction endpoints
fwcd Apr 5, 2019
42511b1
Add DiscordEndpointConsumer.createReaction
fwcd Apr 5, 2019
acd369c
Set callback in DiscordEndpointConsumer.createReaction to nil by default
fwcd Apr 5, 2019
4c19a3b
URL-encode emojis
fwcd Apr 5, 2019
4582c77
Add HTTP 204 to the allowed reponse status codes
fwcd Apr 5, 2019
d67df86
Handle 204 response separately
fwcd Apr 5, 2019
4e0fc00
Provide null coalescing default value in default implementation of Di…
fwcd Apr 5, 2019
1d3748f
Add 'type' parameter to logging call in DiscordJSON.jsonFromResponse
fwcd Apr 5, 2019
c91d410
Merge pull request #79 from fwcd/master
nuclearace Apr 16, 2019
0fc784c
Remove DiscordOpus
TellowKrinkle Nov 10, 2019
1f531d9
Update readme
TellowKrinkle Nov 14, 2019
1cc0ffe
Merge pull request #87 from tellowkrinkle/RemoveDiscordOpus
nuclearace Nov 14, 2019
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
31 changes: 2 additions & 29 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,13 @@
"version": "1.1.0"
}
},
{
"package": "SSCommonCrypto",
"repositoryURL": "https://github.com/daltoniam/common-crypto-spm",
"state": {
"branch": null,
"revision": "2eb3aff0fb57f92f5722fac5d6d20bf64669ca66",
"version": "1.1.0"
}
},
{
"package": "COPUS",
"repositoryURL": "https://github.com/nuclearace/copus",
"state": {
"branch": null,
"revision": "365743902efc1c93730757cea288bef4b90637a0",
"version": "2.0.0"
"revision": "a2af57fa582c0191789f446cc430615ee7e41d4f",
"version": "2.1.1"
}
},
{
Expand Down Expand Up @@ -100,15 +91,6 @@
"version": "2.0.0"
}
},
{
"package": "Starscream",
"repositoryURL": "https://github.com/daltoniam/Starscream",
"state": {
"branch": null,
"revision": "114e5df9b6251970a069e8f1c0cbb5802759f0a9",
"version": "3.0.5"
}
},
{
"package": "TLS",
"repositoryURL": "https://github.com/vapor/tls.git",
Expand All @@ -117,15 +99,6 @@
"revision": "02a47309249e69358aa3c28b5853897585d7a750",
"version": "2.1.2"
}
},
{
"package": "SSCZLib",
"repositoryURL": "https://github.com/daltoniam/zlib-spm.git",
"state": {
"branch": null,
"revision": "83ac8d719a2f3aa775dbdf116a57f56fb2c49abb",
"version": "1.1.0"
}
}
]
},
Expand Down
5 changes: 2 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
import PackageDescription

var deps: [Package.Dependency] = [
.package(url: "https://github.com/nuclearace/copus", .upToNextMinor(from: "2.0.0")),
.package(url: "https://github.com/nuclearace/copus", .upToNextMinor(from: "2.1.1")),
.package(url: "https://github.com/nuclearace/Sodium", .upToNextMinor(from: "2.0.0")),
.package(url: "https://github.com/vapor/engine", .upToNextMinor(from: "2.2.0")),
]

var targetDeps: [Target.Dependency] = ["DiscordOpus", "WebSockets"]
var targetDeps: [Target.Dependency] = ["WebSockets"]

#if !os(Linux)
deps += [.package(url: "https://github.com/daltoniam/Starscream", .upToNextMinor(from: "3.0.0")),]
Expand All @@ -41,7 +41,6 @@ let package = Package(
dependencies: deps,
targets: [
.target(name: "SwiftDiscord", dependencies: targetDeps),
.target(name: "DiscordOpus"),
.testTarget(name: "SwiftDiscordTests", dependencies: ["SwiftDiscord"]),
]
)
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ A Discord API client for Swift.
- Create your Swift Package Manager project
- Add `.package(url: "https://github.com/nuclearace/SwiftDiscord", .upToNextMajor(from: "6.0.0"))` to your dependencies in Package.swift
- Add `import SwiftDiscord` to files you wish to use the module in.
- Run `swift build -Xlinker -L/usr/local/lib -Xlinker -lopus -Xcc -I/usr/local/include`. The Xlinker options are needed to tell the package manager where to find the libsodium and opus libraries that were installed through Homebrew. The Xcc option tells clang where to find the headers for opus.
- Run `swift build`

Xcode:

If you wish to use Xcode with your Swift Package Manager project, you can do `swift package generate-xcodeproj`. However after doing that, you'll have to make a change to SwiftDiscord's build settings. Just like when compiling from the command line, we have to tell Xcode where to find libsodium and libopus. This can be done by adding `/usr/local/lib` to the library search paths and `/usr/local/include` to the header search paths. This should be done for the SwiftDiscord and DiscordOpus targets. The DiscordOpus target also needs the `-lopus` option in "Other Linker Flags".
If you wish to use Xcode with your Swift Package Manager project, you can do `swift package generate-xcodeproj`. In Xcode 11 and higher, you can also add SwiftDiscord as a dependency under the `Link Binary With Libraries` section of the `Build Phases` tab of an existing Xcode project.

![](https://i.imgur.com/JR97eTO.png)

Expand Down
33 changes: 0 additions & 33 deletions Sources/DiscordOpus/configure.c

This file was deleted.

26 changes: 0 additions & 26 deletions Sources/DiscordOpus/include/configure.h

This file was deleted.

6 changes: 6 additions & 0 deletions Sources/SwiftDiscord/DiscordJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ enum JSON {
return nil
}

guard response.statusCode != 204 else {
DefaultDiscordLogger.Logger.debug("Response code 204: No content", type: "JSON")

return nil
}

guard response.statusCode == 200 || response.statusCode == 201 else {
DefaultDiscordLogger.Logger.error("Invalid response code \(response.statusCode)", type: "JSON")
DefaultDiscordLogger.Logger.error("Response: \(stringData)", type: "JSON")
Expand Down
15 changes: 1 addition & 14 deletions Sources/SwiftDiscord/Gateway/DiscordGateway.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,29 +164,16 @@ extension DiscordGatewayPayloadData {
guard let data = data else { return .null }

// TODO this is very ugly. See https://bugs.swift.org/browse/SR-5863
#if !os(Linux)
switch data {
case let object as [String: Any]:
return .object(object)
case let number as NSNumber where number === kCFBooleanTrue || number === kCFBooleanFalse:
case let number as NSNumber where number === (true as NSNumber) || number === (false as NSNumber):
return .bool(number.boolValue)
case let integer as Int:
return .integer(integer)
default:
return .null
}
#else
switch data {
case let object as [String: Any]:
return .object(object)
case let bool as Bool:
return .bool(bool)
case let integer as Int:
return .integer(integer)
default:
return .null
}
#endif
}
}

Expand Down
17 changes: 17 additions & 0 deletions Sources/SwiftDiscord/Rest/DiscordEndpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ public enum DiscordEndpoint : CustomStringConvertible {
/// The channel typing endpoint.
case typing(channel: ChannelID)

// Reactions
/// The endpoint for creating/deleting own reactions.
case reactions(channel: ChannelID, message: MessageID, emoji: String)

/// The endpoint for another user's reactions
case userReactions(channel: ChannelID, message: MessageID, emoji: String, user: UserID)

// Permissions
/// The base channel permissions endpoint.
case permissions(channel: ChannelID)
Expand Down Expand Up @@ -264,6 +271,11 @@ public extension DiscordEndpoint {
return "/channels/\(channel)/messages/\(message)"
case let .typing(channel):
return "/channels/\(channel)/typing"
// Reactions
case let .reactions(channel, message, emoji):
return "/channels/\(channel)/messages/\(message)/reactions/\(emoji)/@me"
case let .userReactions(channel, message, emoji, user):
return "/channels/\(channel)/messages/\(message)/reactions/\(emoji)/\(user)"
// Permissions
case let .permissions(channel):
return "/channels/\(channel)/permissions"
Expand Down Expand Up @@ -362,6 +374,11 @@ public extension DiscordEndpoint {
return DiscordRateLimitKey(id: channel, urlParts: [.channels, .channelID, .messagesDelete, .messageID])
case let .typing(channel):
return DiscordRateLimitKey(id: channel, urlParts: [.channels, .channelID, .typing])
// Reactions
case let .reactions(channel, _, _):
return DiscordRateLimitKey(id: channel, urlParts: [.channels, .channelID, .messages, .messageID, .reactions, .emoji, .me])
case let .userReactions(channel, _, _, _):
return DiscordRateLimitKey(id: channel, urlParts: [.channels, .channelID, .messages, .messageID, .reactions, .emoji, .userID])
// Permissions
case let .permissions(channel):
return DiscordRateLimitKey(id: channel, urlParts: [.channels, .channelID, .permissions])
Expand Down
65 changes: 65 additions & 0 deletions Sources/SwiftDiscord/Rest/DiscordEndpointConsumer+Channels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ public extension DiscordEndpointConsumer where Self: DiscordUserActor {
callback: requestCallback)
}

/// Default implementation
public func createReaction(for messageId: MessageID,
on channelId: ChannelID,
emoji: String,
callback: ((DiscordMessage?, HTTPURLResponse?) -> ())? = nil) {
let requestCallback: DiscordRequestCallback = { data, response, error in
guard case let .object(message)? = JSON.jsonFromResponse(data: data, response: response) else {
callback?(nil, response)
return
}

callback?(DiscordMessage(messageObject: message, client: nil), response)
}

rateLimiter.executeRequest(endpoint: .reactions(channel: channelId, message: messageId, emoji: emoji.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? emoji),
token: token,
requestInfo: .put(content: nil, extraHeaders: nil),
callback: requestCallback)
}

/// Default implementation
public func deleteChannel(_ channelId: ChannelID,
reason: String? = nil,
Expand Down Expand Up @@ -338,6 +358,51 @@ public extension DiscordEndpointConsumer where Self: DiscordUserActor {
callback: requestCallback)
}

/**
Sends multiple messages in a row

Guarantees that the messages will be sent (and received by Discord) in the specified order
- parameter messages: The list of messages to send
- parameter channelID: The ID of the channel to send the messages to
- parameter callback: The function that will be called after all messages are sent or one fails to send.
The HTTPURLResponse will be from the last attempt to send a message (first failure or final success).
If all messages were sent successfully, the length of the array will be the same as the length of the input.
Otherwise, the callback's array will be shorter.
*/
public func sendMessages(_ messages: [DiscordMessage],
to channelID: ChannelID,
callback: (([DiscordMessage], HTTPURLResponse?) -> ())? = nil ) {
guard let firstMessage = messages.first else {
callback?([], nil)
return
}

var messagesToSend = messages.dropFirst()
var sentMessages: [DiscordMessage] = []

// This function strongly captures `self` (which, being a protocol that doesn't require
// its implementors to be classes, can't be made weak). It shouldn't lead to any reference
// cycles due to the fact that `self` never holds onto a reference to the function.
// It does, however, keep `self` alive until all messages are sent. If this is undesirable,
// maybe we should include an `: AnyClass` on `DiscordEndpointConsumer`
func handlerFunc(sentMessage: DiscordMessage?, response: HTTPURLResponse?) {
guard let sentMessage = sentMessage else {
callback?(sentMessages, response)
return
}
if callback != nil { // Save a bit of memory in the case that we won't need `sentMessages`
sentMessages.append(sentMessage)
}
guard let nextMessage = messagesToSend.first else {
callback?(sentMessages, response)
return
}
messagesToSend = messagesToSend.dropFirst()
sendMessage(nextMessage, to: channelID, callback: handlerFunc)
}
sendMessage(firstMessage, to: channelID, callback: handlerFunc)
}

/// Default implementation
public func triggerTyping(on channelId: ChannelID,
callback: ((Bool, HTTPURLResponse?) -> ())? = nil) {
Expand Down
13 changes: 13 additions & 0 deletions Sources/SwiftDiscord/Rest/DiscordEndpointConsumer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ public protocol DiscordEndpointConsumer {
reason: String?,
callback: @escaping (DiscordInvite?, HTTPURLResponse?) -> ())

///
/// Creates a reaction for the specified message.
///
/// - parameter for: The message that is to be edited's snowflake id
/// - parameter on: The channel that we are editing on
/// - parameter emoji: The emoji name
/// - parameter callback: An optional callback containing the edited message, if successful.
///
func createReaction(for messageId: MessageID,
on channelId: ChannelID,
emoji: String,
callback: ((DiscordMessage?, HTTPURLResponse?) -> ())?)

///
/// Deletes the specified channel.
///
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftDiscord/Rest/DiscordRateLimiter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ public struct DiscordRateLimitKey : Hashable {
static let slack = DiscordRateLimitURLParts(rawValue: 1 << 23)
static let github = DiscordRateLimitURLParts(rawValue: 1 << 24)
static let auditLog = DiscordRateLimitURLParts(rawValue: 1 << 25)
static let reactions = DiscordRateLimitURLParts(rawValue: 1 << 26)
static let emoji = DiscordRateLimitURLParts(rawValue: 1 << 27)
static let me = DiscordRateLimitURLParts(rawValue: 1 << 28)

public init(rawValue: Int) {
self.rawValue = rawValue
Expand Down
10 changes: 5 additions & 5 deletions Sources/SwiftDiscord/Voice/DiscordOpusCoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// DEALINGS IN THE SOFTWARE.

import COPUS
import DiscordOpus
import Foundation

/// Declares that a type has enough information to encode/decode Opus data.
Expand Down Expand Up @@ -93,9 +92,10 @@ open class DiscordOpusEncoder : DiscordOpusCodeable {
var err = 0 as Int32

encoderState = opus_encoder_create(Int32(sampleRate), Int32(channels), OPUS_APPLICATION_VOIP, &err)
err = configure_encoder(encoderState, Int32(bitrate), vbr ? 1 : 0)
let err2 = opus_encoder_set_bitrate(encoderState, Int32(bitrate))
let err3 = opus_encoder_set_vbr(encoderState, vbr ? 1 : 0)

guard err == 0 else {
guard err == 0, err2 == 0, err3 == 0 else {
destroyState()

throw DiscordVoiceError.creationFail
Expand Down Expand Up @@ -163,9 +163,9 @@ open class DiscordOpusDecoder : DiscordOpusCodeable {
var err = 0 as Int32

decoderState = opus_decoder_create(Int32(sampleRate), Int32(channels), &err)
err = configure_decoder(decoderState, Int32(gain))
let err2 = opus_decoder_set_gain(decoderState, Int32(gain))

guard err == 0 else {
guard err == 0, err2 == 0 else {
destroyState()

throw DiscordVoiceError.creationFail
Expand Down
1 change: 0 additions & 1 deletion Sources/SwiftDiscord/Voice/DiscordVoiceDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// DEALINGS IN THE SOFTWARE.

import COPUS
import DiscordOpus
import Dispatch
import Foundation

Expand Down
1 change: 0 additions & 1 deletion Sources/SwiftDiscord/Voice/DiscordVoiceDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// DEALINGS IN THE SOFTWARE.

import COPUS
import DiscordOpus
import Foundation

/// Class that decodes Opus voice data into raw PCM data for a VoiceEngine. It can decode multiple streams. Decoding is
Expand Down
Loading