class BBS::DiscordWebhook
Posts messages to a Discord channel through its webhook URL. Plain Ruby with no other part of the gem, so a board’s domain can use it without the telnet server:
require 'bbs/discord_webhook' discord = BBS::DiscordWebhook.new(ENV['DISCORD_WEBHOOK'], label: 'feedia: Discord') discord.post("📨 **#{BBS::DiscordWebhook.escape(name)}** wrote to the admins")
A post goes out in a thread of its own, so a slow webhook never stalls a call. Mentions are off (a caller cannot ping @everyone), the content is cut at max characters, and at most relay_max posts go out in relay_window seconds, however many callers post, so a crowd cannot flood the channel: the rest are dropped and logged. Errors and answers other than 2xx are logged (BBS.log, with label as the tag), never raised. Without a URL (nil or empty) it is off and posts nothing.
Constants
- MARKDOWN
-
The characters of Discord’s markdown (and @), which
::escapeescapes. - MAX
-
The default most characters of a post’s content (Discord takes 2000).
- RELAY_MAX
-
The default most posts in a
RELAY_WINDOW. - RELAY_WINDOW
-
The default window of the relay limit, in seconds.
- SUPPRESS_EMBEDS
-
The message flag that turns off the link previews (embeds).
- TIMEOUT
-
The default seconds to wait for the connection and for each read and write.
Attributes
The webhook’s URI, or nil when it is off.
Public Class Methods
Source
# File lib/bbs/discord_webhook.rb, line 45 def self.clip(text, limit) flat = text.to_s.gsub(/\s+/, ' ').strip flat.length > limit ? "#{flat[0, limit]}…" : flat end
text on one line (runs of whitespace one space, stripped), cut to limit characters with an ellipsis after. Not escaped.
Source
# File lib/bbs/discord_webhook.rb, line 41 def self.escape(text) = text.to_s.gsub(MARKDOWN) { "\\#{Regexp.last_match(1)}" }
text with Discord’s markdown characters (and @, links included) backslash-escaped, so a caller’s text shows as typed.
# File lib/bbs/discord_webhook.rb, line 64 def initialize(url, max: MAX, relay_max: RELAY_MAX, relay_window: RELAY_WINDOW, embeds: true, timeout: TIMEOUT, label: 'Discord') @uri = url.to_s.empty? ? nil : URI(url.to_s) @max = max @relay = relay_max && RateLimit.new(limit: relay_max, per: relay_window) @embeds = embeds @timeout = timeout @label = label end
Creates a webhook client for url (a String or URI; nil or empty: off).
- max
-
the most characters of a post’s content
- relay_max
-
the most posts in
relay_windowseconds;nilfor no limit - relay_window
-
the window of the relay limit, in seconds
- embeds
-
false to post with
SUPPRESS_EMBEDS: no link previews - timeout
-
seconds to wait for the connection, and for each read and write
- label
-
the tag of its
BBS.loglines
Public Instance Methods
Source
# File lib/bbs/discord_webhook.rb, line 75 def enabled? = !@uri.nil?
Whether it has a URL to post to.
Source
# File lib/bbs/discord_webhook.rb, line 82 def post(content) return unless enabled? return BBS.log(@label, 'relay limit reached, not sent') unless @relay.nil? || @relay.allow?(:posts) body = { content: content.to_s[0, @max], allowed_mentions: { parse: [] } } body[:flags] = SUPPRESS_EMBEDS unless @embeds payload = JSON.generate(body) Thread.new { deliver(payload) } end
Posts content (cut at max) in a background thread, mentions off. Thread-safe.
Returns the Thread (join it to wait for the post), or nil when the webhook is off or the relay limit is reached (logged).