Module: MijDiscord::Core::API

Defined in:
lib/mij-discord/core/api.rb

Defined Under Namespace

Modules: Channel, Invite, Server, User

Constant Summary collapse

APIBASE_URL =
'https://discordapp.com/api/v6'
CDN_URL =
'https://cdn.discordapp.com'

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.bot_nameObject

Returns the value of attribute bot_name.



9
10
11
# File 'lib/mij-discord/core/api.rb', line 9

def bot_name
  @bot_name
end

Class Method Details

.acknowledge_message(auth, channel_id, message_id) ⇒ Object

Acknowledge that a message has been received The last acknowledged message will be sent in the ready packet, so this is an easy way to catch up on messages



112
113
114
115
116
117
118
119
120
121
# File 'lib/mij-discord/core/api.rb', line 112

def acknowledge_message(auth, channel_id, message_id)
  request(
    :channels_cid_messages_mid_ack,
    nil, # This endpoint is unavailable for bot accounts and thus isn't subject to its rate limit requirements.
    :post,
    "#{APIBASE_URL}/channels/#{channel_id}/messages/#{message_id}/ack",
    nil,
    Authorization: auth
  )
end

.app_icon_url(app_id, icon_id, format = :webp) ⇒ Object

Make an icon URL from application and icon IDs



29
30
31
# File 'lib/mij-discord/core/api.rb', line 29

def app_icon_url(app_id, icon_id, format = :webp)
  "#{CDN_URL}/app-icons/#{app_id}/#{icon_id}.#{format}"
end

.create_oauth_application(auth, name, redirect_uris) ⇒ Object

Create an OAuth application



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/mij-discord/core/api.rb', line 73

def create_oauth_application(auth, name, redirect_uris)
  request(
    :oauth2_applications,
    nil,
    :post,
    "#{APIBASE_URL}/oauth2/applications",
    { name: name, redirect_uris: redirect_uris }.to_json,
    Authorization: auth,
    content_type: :json
  )
end

.emoji_icon_url(emoji_id, format = :webp) ⇒ Object

Make an emoji icon URL from emoji ID



44
45
46
# File 'lib/mij-discord/core/api.rb', line 44

def emoji_icon_url(emoji_id, format = :webp)
  "#{CDN_URL}/emojis/#{emoji_id}.#{format}"
end

.gateway(auth) ⇒ Object

Get the gateway to be used



124
125
126
127
128
129
130
131
132
# File 'lib/mij-discord/core/api.rb', line 124

def gateway(auth)
  request(
    :gateway,
    nil,
    :get,
    "#{APIBASE_URL}/gateway",
    Authorization: auth,
  )
end

.icon_url(server_id, icon_id, format = :webp) ⇒ Object

Make an icon URL from server and icon IDs



24
25
26
# File 'lib/mij-discord/core/api.rb', line 24

def icon_url(server_id, icon_id, format = :webp)
  "#{CDN_URL}/icons/#{server_id}/#{icon_id}.#{format}"
end

.login(email, password) ⇒ Object

Login to the server



49
50
51
52
53
54
55
56
57
58
# File 'lib/mij-discord/core/api.rb', line 49

def (email, password)
  request(
    :auth_login,
    nil,
    :post,
    "#{APIBASE_URL}/auth/login",
    email: email,
    password: password
  )
end

.logout(auth) ⇒ Object

Logout from the server



61
62
63
64
65
66
67
68
69
70
# File 'lib/mij-discord/core/api.rb', line 61

def logout(auth)
  request(
    :auth_logout,
    nil,
    :post,
    "#{APIBASE_URL}/auth/logout",
    nil,
    Authorization: auth
  )
end

.oauth_application(auth) ⇒ Object

Get the bot’s OAuth application’s information



99
100
101
102
103
104
105
106
107
# File 'lib/mij-discord/core/api.rb', line 99

def oauth_application(auth)
  request(
    :oauth2_applications_me,
    nil,
    :get,
    "#{APIBASE_URL}/oauth2/applications/@me",
    Authorization: auth
  )
end

.raw_request(type, attributes) ⇒ Object



159
160
161
162
163
164
165
166
# File 'lib/mij-discord/core/api.rb', line 159

def raw_request(type, attributes)
  RestClient.send(type, *attributes)
rescue RestClient::Forbidden
  raise MijDiscord::Core::Errors::NoPermission
rescue RestClient::BadGateway
  MijDiscord::LOGGER.warn('HTTP') { 'Received 502 Bad Gateway during API request' }
  retry
end

.request(key, major_param, type, *attributes) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/mij-discord/core/api.rb', line 168

def request(key, major_param, type, *attributes)
  ratelimit_delta, response = nil, nil

  if (params = attributes.last).is_a?(Hash)
    params[:user_agent] = user_agent(params[:Authorization])
    ratelimit_delta = params.delete(:header_bypass_delay)
  end

  key = [key, major_param].freeze
  key_mutex = (@rate_limit_mutex[key] ||= Mutex.new)
  global_mutex = @rate_limit_mutex[:global]

  begin
    mutex_wait(key_mutex)
    mutex_wait(global_mutex) if global_mutex.locked?

    response = raw_request(type, attributes)
  rescue RestClient::TooManyRequests => e
    response = e.response

    is_global = response.headers[:x_ratelimit_global]
    mutex = is_global == 'true' ? global_mutex : key_mutex

    unless mutex.locked?
      response = JSON.parse(e.response)
      retry_after = response['retry_after'].to_i / 1000.0

      MijDiscord::LOGGER.info('HTTP') { "Hit Discord rate limit on <#{key}>, waiting for #{retry_after} seconds" }
      sync_wait(retry_after, mutex)
    end

    retry
  rescue RestClient::Exception => e
    response = e.response
    raise
  ensure
    headers = response&.headers
    if headers && headers[:x_ratelimit_remaining] == '0' && !key_mutex.locked?
      unless ratelimit_delta
        now = Time.rfc2822(headers[:date])
        reset = Time.at(headers[:x_ratelimit_reset].to_i)
        ratelimit_delta = reset - now
      end

      sync_wait(ratelimit_delta, key_mutex)
    end
  end

  response
end

.splash_url(server_id, splash_id) ⇒ Object

Make a splash URL from server and splash IDs



39
40
41
# File 'lib/mij-discord/core/api.rb', line 39

def splash_url(server_id, splash_id)
  "#{CDN_URL}{/splashes/#{server_id}/#{splash_id}.jpg"
end

.update_oauth_application(auth, name, redirect_uris, description = '', icon = nil) ⇒ Object

Change an OAuth application’s properties



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/mij-discord/core/api.rb', line 86

def update_oauth_application(auth, name, redirect_uris, description = '', icon = nil)
  request(
    :oauth2_applications,
    nil,
    :put,
    "#{APIBASE_URL}/oauth2/applications",
    { name: name, redirect_uris: redirect_uris, description: description, icon: icon }.to_json,
    Authorization: auth,
    content_type: :json
  )
end

.user_agent(auth) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/mij-discord/core/api.rb', line 11

def user_agent(auth)
  case auth&.type
    when :bot
      bot_name = @bot_name || 'generic'
      ua_base = "DiscordBot (https://github.com/Mijyuoon/mij-discord, v#{MijDiscord::VERSION})"
      "#{ua_base} mij-discord/#{MijDiscord::VERSION} #{bot_name}"

    when :user
      'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0'
  end
end

.validate_token(auth) ⇒ Object

Validate a token (this request will fail if the token is invalid)



135
136
137
138
139
140
141
142
143
144
145
# File 'lib/mij-discord/core/api.rb', line 135

def validate_token(auth)
  request(
    :auth_login,
    nil,
    :post,
    "#{APIBASE_URL}/auth/login",
    {}.to_json,
    Authorization: auth,
    content_type: :json
  )
end

.voice_regions(auth) ⇒ Object

Get a list of available voice regions



148
149
150
151
152
153
154
155
156
157
# File 'lib/mij-discord/core/api.rb', line 148

def voice_regions(auth)
  request(
    :voice_regions,
    nil,
    :get,
    "#{APIBASE_URL}/voice/regions",
    Authorization: auth,
    content_type: :json
  )
end

.widget_url(server_id, style = 'shield') ⇒ Object

Make a widget picture URL from server ID



34
35
36
# File 'lib/mij-discord/core/api.rb', line 34

def widget_url(server_id, style = 'shield')
  "#{APIBASE_URL}/guilds/#{server_id}/widget.png?style=#{style}"
end