Class: DiscordStore::Configuration
- Inherits:
-
Object
- Object
- DiscordStore::Configuration
- Defined in:
- lib/discord_store/configuration.rb
Overview
Process-wide settings. Most applications configure this once at boot:
DiscordStore.configure do |c|
c.i_understand_this_violates_discord_tos = true
c.token = ENV.fetch("DISCORD_BOT_TOKEN")
c.application_id = ENV.fetch("DISCORD_APPLICATION_ID")
c.guild_id = ENV.fetch("DISCORD_GUILD_ID")
c.secret_key = ENV.fetch("DISCORD_STORE_KEY") # 32 raw bytes, base64
end
Constant Summary collapse
- DISCORD_GLOBAL_LIMIT =
Discord's documented global ceiling for a bot token, in requests/second. We aim below it by default; see #global_rate_limit.
50- MESSAGE_CONTENT_LIMIT =
Maximum characters in a normal message's
contentfield. 2000- DEFAULTS =
Every setting that has a sensible default, and its default.
{ global_rate_limit: 45, quota_timeout: 15.0, max_retries: 5, # Discord answers 202 with retry_after 0 when it has no better estimate, # and says to "retry after a short delay". This is what short means. # Tests drop it so the suite exercises the retry rather than sleeping # through it, which is the same reason the fake's rate limit is settable. search_retry_floor: 0.5, open_timeout: 5.0, read_timeout: 30.0, write_timeout: 30.0, user_agent: nil, api_base: "https://discord.com/api/v10", cipher: :aes_256_gcm, content_budget: 1900, max_concurrent_transfers: 24, chunk_size: nil, delete_policy: :tombstone, own_messages_only: true, logger: nil }.freeze
Instance Attribute Summary collapse
-
#api_base ⇒ Object
--- Transport -----------------------------------------------------------.
-
#application_id ⇒ Object
The bot's application (user) ID.
-
#blob_channel_ids ⇒ Object
Channels used for blob chunks (ActiveStorage).
-
#chunk_size ⇒ Object
Bytes per blob chunk.
-
#cipher ⇒ Object
:aes_256_gcm (default) or :none.
-
#content_budget ⇒ Object
How many characters of a message's content we are willing to fill.
-
#delete_policy ⇒ Object
What to do when a blob or record is deleted:.
-
#document_channel_id ⇒ Object
Channel used for mutable documents (the KV layer).
-
#global_rate_limit ⇒ Object
--- Transport -----------------------------------------------------------.
-
#guild_id ⇒ Object
The guild that owns the channels we write to.
-
#i_understand_this_violates_discord_tos ⇒ Object
Storing application data in Discord messages violates the Discord Developer Terms of Service.
-
#log_channel_ids ⇒ Object
Channels used for the append-only log.
-
#logger ⇒ Object
--- Transport -----------------------------------------------------------.
-
#manifest_channel_id ⇒ Object
Channel holding blob manifests.
-
#max_concurrent_transfers ⇒ Object
Concurrency ceiling for blob chunk transfers.
-
#max_retries ⇒ Object
--- Transport -----------------------------------------------------------.
-
#open_timeout ⇒ Object
--- Transport -----------------------------------------------------------.
-
#own_messages_only ⇒ Object
Refuse to read any message not authored by
application_id. -
#quota_timeout ⇒ Object
--- Transport -----------------------------------------------------------.
-
#read_timeout ⇒ Object
--- Transport -----------------------------------------------------------.
-
#search_retry_floor ⇒ Object
--- Transport -----------------------------------------------------------.
-
#secret_key ⇒ Object
32 raw bytes, base64-encoded.
-
#token ⇒ Object
Bot token, without the "Bot " prefix.
-
#user_agent ⇒ Object
--- Transport -----------------------------------------------------------.
-
#write_timeout ⇒ Object
--- Transport -----------------------------------------------------------.
Instance Method Summary collapse
-
#all_channel_ids ⇒ Array<String>
Every channel this configuration knows about, deduplicated.
-
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
-
#secret_key_bytes ⇒ String?
The raw 32-byte encryption key.
- #validate! ⇒ void
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
123 124 125 126 127 128 |
# File 'lib/discord_store/configuration.rb', line 123 def initialize DEFAULTS.each { |name, value| public_send(:"#{name}=", value) } @i_understand_this_violates_discord_tos = false @log_channel_ids = [] @blob_channel_ids = [] end |
Instance Attribute Details
#api_base ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def api_base @api_base end |
#application_id ⇒ Object
The bot's application (user) ID. Used to enforce that we only ever read messages our own bot wrote. Strongly recommended; see #own_messages_only.
59 60 61 |
# File 'lib/discord_store/configuration.rb', line 59 def application_id @application_id end |
#blob_channel_ids ⇒ Object
Channels used for blob chunks (ActiveStorage). Sharded like the log.
72 73 74 |
# File 'lib/discord_store/configuration.rb', line 72 def blob_channel_ids @blob_channel_ids end |
#chunk_size ⇒ Object
Bytes per blob chunk. Left nil to be discovered at runtime from the guild's boost tier, because Discord's attachment ceiling has moved several times and hardcoding it is how these libraries break.
113 114 115 |
# File 'lib/discord_store/configuration.rb', line 113 def chunk_size @chunk_size end |
#cipher ⇒ Object
:aes_256_gcm (default) or :none. :none writes readable JSON into the channel, which is useful when you want humans to read the data in the Discord client, and which forfeits the encryption-at-rest that Discord's own developer terms require of anyone storing end-user data.
87 88 89 |
# File 'lib/discord_store/configuration.rb', line 87 def cipher @cipher end |
#content_budget ⇒ Object
How many characters of a message's content we are willing to fill. Kept under MESSAGE_CONTENT_LIMIT so that framing overhead can never push a message over the hard limit.
105 106 107 |
# File 'lib/discord_store/configuration.rb', line 105 def content_budget @content_budget end |
#delete_policy ⇒ Object
What to do when a blob or record is deleted:
:tombstone — edit the message to a tombstone marker, never delete.
Cheapest, and survives the 14-day bulk-delete window.
:bulk — bulk-delete where possible, tombstone the rest.
:aggressive — delete everything, one request at a time if we must.
121 122 123 |
# File 'lib/discord_store/configuration.rb', line 121 def delete_policy @delete_policy end |
#document_channel_id ⇒ Object
Channel used for mutable documents (the KV layer).
69 70 71 |
# File 'lib/discord_store/configuration.rb', line 69 def document_channel_id @document_channel_id end |
#global_rate_limit ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def global_rate_limit @global_rate_limit end |
#guild_id ⇒ Object
The guild that owns the channels we write to.
62 63 64 |
# File 'lib/discord_store/configuration.rb', line 62 def guild_id @guild_id end |
#i_understand_this_violates_discord_tos ⇒ Object
Storing application data in Discord messages violates the Discord Developer Terms of Service. Nothing in this library will make a network request until this is explicitly set to true.
50 51 52 |
# File 'lib/discord_store/configuration.rb', line 50 def i_understand_this_violates_discord_tos @i_understand_this_violates_discord_tos end |
#log_channel_ids ⇒ Object
Channels used for the append-only log. More than one channel multiplies write throughput, because Discord's harshest message limit is per-channel.
66 67 68 |
# File 'lib/discord_store/configuration.rb', line 66 def log_channel_ids @log_channel_ids end |
#logger ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def logger @logger end |
#manifest_channel_id ⇒ Object
Channel holding blob manifests. Kept separate from chunks so that a manifest scan does not have to page past gigabytes of chunk messages.
76 77 78 |
# File 'lib/discord_store/configuration.rb', line 76 def manifest_channel_id @manifest_channel_id end |
#max_concurrent_transfers ⇒ Object
Concurrency ceiling for blob chunk transfers.
108 109 110 |
# File 'lib/discord_store/configuration.rb', line 108 def max_concurrent_transfers @max_concurrent_transfers end |
#max_retries ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def max_retries @max_retries end |
#open_timeout ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def open_timeout @open_timeout end |
#own_messages_only ⇒ Object
Refuse to read any message not authored by application_id. This is the
line between a storage backend and a scraper, and it is enforced in code
rather than in documentation. Leave it on.
98 99 100 |
# File 'lib/discord_store/configuration.rb', line 98 def @own_messages_only end |
#quota_timeout ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def quota_timeout @quota_timeout end |
#read_timeout ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def read_timeout @read_timeout end |
#search_retry_floor ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def search_retry_floor @search_retry_floor end |
#secret_key ⇒ Object
32 raw bytes, base64-encoded. Required unless cipher is :none.
81 82 83 |
# File 'lib/discord_store/configuration.rb', line 81 def secret_key @secret_key end |
#token ⇒ Object
Bot token, without the "Bot " prefix.
55 56 57 |
# File 'lib/discord_store/configuration.rb', line 55 def token @token end |
#user_agent ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def user_agent @user_agent end |
#write_timeout ⇒ Object
--- Transport -----------------------------------------------------------
91 92 93 |
# File 'lib/discord_store/configuration.rb', line 91 def write_timeout @write_timeout end |
Instance Method Details
#all_channel_ids ⇒ Array<String>
Every channel this configuration knows about, deduplicated.
165 166 167 168 169 170 171 172 |
# File 'lib/discord_store/configuration.rb', line 165 def all_channel_ids [ *log_channel_ids, *blob_channel_ids, document_channel_id, manifest_channel_id ].compact.map(&:to_s).uniq end |
#secret_key_bytes ⇒ String?
The raw 32-byte encryption key.
152 153 154 155 156 157 158 159 160 |
# File 'lib/discord_store/configuration.rb', line 152 def secret_key_bytes return nil if cipher == :none return nil if blank?(secret_key) require "base64" Base64.strict_decode64(secret_key.to_s) rescue ArgumentError raise ConfigurationError, "secret_key is not valid base64" end |
#validate! ⇒ void
This method returns an undefined value.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/discord_store/configuration.rb', line 133 def validate! raise UnacknowledgedError unless i_understand_this_violates_discord_tos raise ConfigurationError, "token is required" if blank?(token) if && blank?(application_id) raise ConfigurationError, "application_id is required while own_messages_only is enabled " \ "(it is what makes the check possible). Set it, or explicitly " \ "set own_messages_only = false and accept what that means." end validate_cipher! validate_budget! self end |