Skip to content

Commit

Permalink
Documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Nov 26, 2024
1 parent 538a871 commit 42c50a7
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 2 deletions.
15 changes: 15 additions & 0 deletions lib/async/discord.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

require_relative "discord/version"
require_relative "discord/client"

# @namespace
module Async
# @namespace
module Discord
end
end

20 changes: 20 additions & 0 deletions lib/async/discord/channels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@

module Async
module Discord
# Represents a message in a channel.
class Message < Representation
end

# Represents a channel in a guild.
class Channel < Representation
# Send a message to this channel.
#
# @parameter content [String] The content of the message.
def send_message(content)
payload = {
content: content
Expand All @@ -19,20 +24,32 @@ def send_message(content)
Message.post(@resource.with(path: "messages"), payload)
end

# The unique identifier for this channel.
def id
self.value[:id]
end

# Whether this channel is a text channel.
#
# @returns [Boolean] if this channel is a text channel.
def text?
self.value[:type] == 0
end

# Whether this channel is a voice channel.
#
# @returns [Boolean] if this channel is a voice channel.
def voice?
self.value[:type] == 2
end
end

# Represents a collection of channels.
class Channels < Representation
# Enumerate over each channel.
#
# @yields {|channel| ...}
# @parameter channel [Channel] The channel.
def each(&block)
return to_enum unless block_given?

Expand All @@ -43,6 +60,9 @@ def each(&block)
end
end

# Convert this collection to an array.
#
# @returns [Array(Channel)] an array of channels.
def to_a
each.to_a
end
Expand Down
12 changes: 12 additions & 0 deletions lib/async/discord/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@

module Async
module Discord
# A client for interacting with Discord.
class Client < Async::REST::Resource
# The default endpoint for Discord.
ENDPOINT = Async::HTTP::Endpoint.parse("https://discord.com/api/v10/")

# The default user agent for this client.
USER_AGENT = "#{self.name} (https://github.com/socketry/async-discord, v#{Async::Discord::VERSION})"

# Authenticate the client, either with a bot or bearer token.
#
# @parameter bot [String] The bot token.
# @parameter bearer [String] The bearer token.
# @returns [Client] a new client with the given authentication.
def authenticated(bot: nil, bearer: nil)
headers = {}

Expand All @@ -30,14 +39,17 @@ def authenticated(bot: nil, bearer: nil)
return self.with(headers: headers)
end

# @returns [Guilds] a collection of guilds the bot is a member of.
def guilds
Guilds.new(self.with(path: "users/@me/guilds"))
end

# @returns [Gateway] the gateway for the bot.
def gateway
Gateway.new(self.with(path: "gateway/bot"))
end

# @returns [Channel] a channel by its unique identifier.
def channel(id)
Channel.new(self.with(path: "channels/#{id}"))
end
Expand Down
27 changes: 25 additions & 2 deletions lib/async/discord/gateway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

module Async
module Discord
# Represents a gateway connection to Discord, which can be used to send and receive messages via a WebSocket connection.
class GatewayConnection < Async::WebSocket::Connection
# Gateway Opcodes:
DISPATCH = 0
Expand All @@ -24,7 +25,7 @@ class GatewayConnection < Async::WebSocket::Connection
HEARTBEAT_ACK = 11
REQUEST_SOUNDBOARD_SOUNDS = 31

# Gateway Error Codes
# Gateway Error Codes.
ERROR_CODES = {
4000 => "UNKNOWN_ERROR",
4001 => "UNKNOWN_OPCODE",
Expand All @@ -42,7 +43,7 @@ class GatewayConnection < Async::WebSocket::Connection
4014 => "DISALLOWED_INTENT"
}

# Guild Intents:
# Guild Intents.
module Intent
GUILDS = 1 << 0
GUILD_MEMBERS = 1 << 1
Expand All @@ -67,27 +68,32 @@ module Intent
DIRECT_MESSAGE_POLLS = 1 << 25
end

# Default intent for a bot.
DEFAULT_INTENT = Intent::GUILDS | Intent::GUILD_MESSAGES | Intent::DIRECT_MESSAGES

# Default properties for a bot.
DEFAULT_PROPERTIES = {
os: RUBY_PLATFORM,
browser: Async::Discord.name,
device: Async::Discord.name,
}

# Default presence for a bot.
DEFAULT_PRESENCE = {
status: "online",
afk: false,
activities: [],
}

# Initialize the gateway connection.
def initialize(...)
super

@heartbeat_task = nil
@sequence = nil
end

# Close the gateway connection, including the heartbeat task.
def close(...)
if heartbeat_task = @heartbeat_task
@heartbeat_task = nil
Expand All @@ -97,6 +103,9 @@ def close(...)
super
end

# Identify the bot with the given identity.
#
# @returns [Hash] the payload from the READY event.
def identify(**identity)
while message = self.read
payload = message.parse
Expand Down Expand Up @@ -136,6 +145,10 @@ def identify(**identity)
end
end

# Listen for events from the gateway.
#
# @yields {|payload| ...}
# @parameter payload [Hash] The parsed payload.
def listen
while message = self.read
payload = message.parse
Expand All @@ -158,6 +171,7 @@ def listen

private

# Run a heartbeat task at the given interval.
def run_heartbeat(duration_ms)
duration = duration_ms / 1000.0
Console.debug(self, "Running heartbeat every #{duration} seconds.")
Expand All @@ -177,19 +191,28 @@ def run_heartbeat(duration_ms)
end
end

# Represents a gateway for the bot.
class Gateway < Representation
# The URL of the gateway, used for connecting to the WebSocket server.
def url
self.value[:url]
end

# The number of shards to use.
def shards
self.value[:shards]
end


def session_start_limit
self.value[:session_start_limit]
end

# Connect to the gateway, yielding the connection.
#
# @yields {|connection| ...} if a block is given.
# @parameter connection [GatewayConnection] The connection to the gateway.
# @returns [GatewayConnection] the connection to the gateway.
def connect(shard: nil, &block)
endpoint = Async::HTTP::Endpoint.parse(self.url, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)

Expand Down
13 changes: 13 additions & 0 deletions lib/async/discord/guilds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,26 @@

module Async
module Discord
# Represents a guild in Discord.
class Guild < Representation
# @returns [Channels] a collection of channels in this guild.
def channels
Channels.new(@resource.with(path: "channels"))
end

# The unique identifier for this guild.
def id
self.value[:id]
end
end

# Represents a collection of guilds.
class Guilds < Representation
# Enumerate over each guild.
#
# @yields {|guild| ...} if a block is given.
# @parameter guild [Guild] The guild.
# @returns [Enumerator] if no block is given.
def each(&block)
return to_enum unless block_given?

Expand All @@ -29,10 +38,14 @@ def each(&block)
end
end

# Convert the collection to an array.
#
# @returns [Array(Guild)] the collection as an array.
def to_a
each.to_a
end

# @returns [Boolean] if the collection is empty.
def empty?
self.value.empty?
end
Expand Down
2 changes: 2 additions & 0 deletions lib/async/discord/representation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

module Async
module Discord
# The default wrapper for Discord.
class Wrapper < Async::REST::Wrapper::JSON
end

# The default representation for Discord.
class Representation < Async::REST::Representation[Wrapper]
end
end
Expand Down

0 comments on commit 42c50a7

Please sign in to comment.