discord_store 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +439 -0
- data/lib/active_record/connection_adapters/discord_adapter.rb +271 -0
- data/lib/active_storage/service/discord_service.rb +232 -0
- data/lib/discord_store/blob_store.rb +453 -0
- data/lib/discord_store/channel_shard.rb +73 -0
- data/lib/discord_store/cipher.rb +195 -0
- data/lib/discord_store/codec.rb +231 -0
- data/lib/discord_store/configuration.rb +197 -0
- data/lib/discord_store/errors.rb +92 -0
- data/lib/discord_store/guild_limits.rb +117 -0
- data/lib/discord_store/journal.rb +262 -0
- data/lib/discord_store/kv.rb +387 -0
- data/lib/discord_store/log/record.rb +88 -0
- data/lib/discord_store/log.rb +299 -0
- data/lib/discord_store/railtie.rb +27 -0
- data/lib/discord_store/replay.rb +136 -0
- data/lib/discord_store/snowflake.rb +109 -0
- data/lib/discord_store/tasks.rake +92 -0
- data/lib/discord_store/transport/bucket.rb +141 -0
- data/lib/discord_store/transport/fake.rb +394 -0
- data/lib/discord_store/transport/http.rb +174 -0
- data/lib/discord_store/transport/quota.rb +138 -0
- data/lib/discord_store/transport/rate_limiter.rb +148 -0
- data/lib/discord_store/transport/rest.rb +361 -0
- data/lib/discord_store/version.rb +5 -0
- data/lib/discord_store.rb +125 -0
- metadata +97 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "discord_store/version"
|
|
4
|
+
require_relative "discord_store/errors"
|
|
5
|
+
require_relative "discord_store/snowflake"
|
|
6
|
+
require_relative "discord_store/configuration"
|
|
7
|
+
require_relative "discord_store/cipher"
|
|
8
|
+
require_relative "discord_store/channel_shard"
|
|
9
|
+
require_relative "discord_store/codec"
|
|
10
|
+
require_relative "discord_store/log"
|
|
11
|
+
require_relative "discord_store/guild_limits"
|
|
12
|
+
require_relative "discord_store/blob_store"
|
|
13
|
+
require_relative "discord_store/kv"
|
|
14
|
+
require_relative "discord_store/transport/http"
|
|
15
|
+
require_relative "discord_store/transport/quota"
|
|
16
|
+
require_relative "discord_store/transport/bucket"
|
|
17
|
+
require_relative "discord_store/transport/rate_limiter"
|
|
18
|
+
require_relative "discord_store/transport/rest"
|
|
19
|
+
require_relative "discord_store/transport/fake"
|
|
20
|
+
|
|
21
|
+
# Uses Discord as a database.
|
|
22
|
+
#
|
|
23
|
+
# It works, in the sense that the data goes in and comes back out. It is also an
|
|
24
|
+
# explicit violation of the Discord Developer Terms of Service, it is capped at
|
|
25
|
+
# a few megabytes per second by rate limits nobody can raise for you, and every
|
|
26
|
+
# byte of it lives at the pleasure of a company that has already shipped one
|
|
27
|
+
# change (signed, expiring CDN links) that broke this entire category of project
|
|
28
|
+
# overnight.
|
|
29
|
+
#
|
|
30
|
+
# Read {Configuration#i_understand_this_violates_discord_tos} before using it.
|
|
31
|
+
module DiscordStore
|
|
32
|
+
class << self
|
|
33
|
+
# @return [Configuration]
|
|
34
|
+
def configuration
|
|
35
|
+
@configuration ||= Configuration.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @yieldparam config [Configuration]
|
|
39
|
+
# @return [Configuration]
|
|
40
|
+
def configure
|
|
41
|
+
yield(configuration) if block_given?
|
|
42
|
+
configuration
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Resets configuration and any memoized client. Mainly for tests.
|
|
46
|
+
#
|
|
47
|
+
# @return [void]
|
|
48
|
+
def reset!
|
|
49
|
+
@configuration = nil
|
|
50
|
+
@client = nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The process-wide client.
|
|
54
|
+
#
|
|
55
|
+
# @return [Client]
|
|
56
|
+
def client
|
|
57
|
+
@client ||= Client.new(config: configuration)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Replaces the process-wide client, e.g. with one wired to the fake.
|
|
61
|
+
#
|
|
62
|
+
# @param client [Client]
|
|
63
|
+
# @return [Client]
|
|
64
|
+
attr_writer :client
|
|
65
|
+
|
|
66
|
+
# @return [String] a fresh base64 encryption key
|
|
67
|
+
def generate_key = Cipher.generate_key
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Ties the layers together: one transport, one rate limiter, and the stores
|
|
71
|
+
# built on top of them.
|
|
72
|
+
class Client
|
|
73
|
+
attr_reader :config, :rest
|
|
74
|
+
|
|
75
|
+
# @param config [Configuration]
|
|
76
|
+
# @param http [#call, nil] injectable HTTP backend; pass a
|
|
77
|
+
# {Transport::Fake} to run the whole stack without a token
|
|
78
|
+
def initialize(config: DiscordStore.configuration, http: nil)
|
|
79
|
+
@config = config.validate!
|
|
80
|
+
@rest = Transport::REST.new(config: @config, http: http)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @return [Log]
|
|
84
|
+
def log
|
|
85
|
+
@log ||= Log.new(rest: @rest, config: @config)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @return [BlobStore]
|
|
89
|
+
def blobs
|
|
90
|
+
@blobs ||= BlobStore.new(rest: @rest, config: @config)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [KV]
|
|
94
|
+
def kv
|
|
95
|
+
@kv ||= KV.new(rest: @rest, config: @config)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @return [GuildLimits]
|
|
99
|
+
def limits
|
|
100
|
+
@limits ||= GuildLimits.new(rest: @rest, config: @config)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Confirms the token works and that the configured application_id matches
|
|
104
|
+
# the token's actual identity. Worth calling at boot: a mismatched
|
|
105
|
+
# application_id silently makes every read return nothing, because the
|
|
106
|
+
# own-messages guard rejects our own writes.
|
|
107
|
+
#
|
|
108
|
+
# @return [Hash] the bot user
|
|
109
|
+
# @raise [ConfigurationError] on an application_id mismatch
|
|
110
|
+
def verify!
|
|
111
|
+
user = @rest.current_user
|
|
112
|
+
|
|
113
|
+
if @config.own_messages_only && user["id"].to_s != @config.application_id.to_s
|
|
114
|
+
raise ConfigurationError,
|
|
115
|
+
"configured application_id #{@config.application_id.inspect} is not this token's " \
|
|
116
|
+
"identity (#{user["id"].inspect}). Every read would silently return nothing."
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
user
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @return [void]
|
|
123
|
+
def close = @rest.close
|
|
124
|
+
end
|
|
125
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: discord_store
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Chayut
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-09-09 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: base64
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.2'
|
|
27
|
+
description: |
|
|
28
|
+
A rate-limit-aware transport, an encrypted append-only log, an ActiveStorage
|
|
29
|
+
service and an ActiveRecord adapter, all backed by Discord messages and
|
|
30
|
+
attachments. Snowflake IDs as log sequence numbers, channels as partitions,
|
|
31
|
+
tombstones instead of deletes, and CDN links re-resolved on every read
|
|
32
|
+
instead of cached. An extended argument about what an ActiveRecord adapter
|
|
33
|
+
is allowed to be, which happens to work.
|
|
34
|
+
email:
|
|
35
|
+
- chayut_o@hotmail.com
|
|
36
|
+
executables: []
|
|
37
|
+
extensions: []
|
|
38
|
+
extra_rdoc_files: []
|
|
39
|
+
files:
|
|
40
|
+
- CHANGELOG.md
|
|
41
|
+
- LICENSE.txt
|
|
42
|
+
- README.md
|
|
43
|
+
- lib/active_record/connection_adapters/discord_adapter.rb
|
|
44
|
+
- lib/active_storage/service/discord_service.rb
|
|
45
|
+
- lib/discord_store.rb
|
|
46
|
+
- lib/discord_store/blob_store.rb
|
|
47
|
+
- lib/discord_store/channel_shard.rb
|
|
48
|
+
- lib/discord_store/cipher.rb
|
|
49
|
+
- lib/discord_store/codec.rb
|
|
50
|
+
- lib/discord_store/configuration.rb
|
|
51
|
+
- lib/discord_store/errors.rb
|
|
52
|
+
- lib/discord_store/guild_limits.rb
|
|
53
|
+
- lib/discord_store/journal.rb
|
|
54
|
+
- lib/discord_store/kv.rb
|
|
55
|
+
- lib/discord_store/log.rb
|
|
56
|
+
- lib/discord_store/log/record.rb
|
|
57
|
+
- lib/discord_store/railtie.rb
|
|
58
|
+
- lib/discord_store/replay.rb
|
|
59
|
+
- lib/discord_store/snowflake.rb
|
|
60
|
+
- lib/discord_store/tasks.rake
|
|
61
|
+
- lib/discord_store/transport/bucket.rb
|
|
62
|
+
- lib/discord_store/transport/fake.rb
|
|
63
|
+
- lib/discord_store/transport/http.rb
|
|
64
|
+
- lib/discord_store/transport/quota.rb
|
|
65
|
+
- lib/discord_store/transport/rate_limiter.rb
|
|
66
|
+
- lib/discord_store/transport/rest.rb
|
|
67
|
+
- lib/discord_store/version.rb
|
|
68
|
+
homepage: https://github.com/chayuto/discord_store
|
|
69
|
+
licenses:
|
|
70
|
+
- MIT
|
|
71
|
+
metadata:
|
|
72
|
+
source_code_uri: https://github.com/chayuto/discord_store
|
|
73
|
+
bug_tracker_uri: https://github.com/chayuto/discord_store/issues
|
|
74
|
+
changelog_uri: https://github.com/chayuto/discord_store/blob/main/CHANGELOG.md
|
|
75
|
+
documentation_uri: https://rubydoc.info/gems/discord_store
|
|
76
|
+
rubygems_mfa_required: 'true'
|
|
77
|
+
post_install_message:
|
|
78
|
+
rdoc_options: []
|
|
79
|
+
require_paths:
|
|
80
|
+
- lib
|
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '3.1'
|
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
requirements: []
|
|
92
|
+
rubygems_version: 3.5.22
|
|
93
|
+
signing_key:
|
|
94
|
+
specification_version: 4
|
|
95
|
+
summary: Use Discord as a database. Against your better judgement, and its Terms of
|
|
96
|
+
Service.
|
|
97
|
+
test_files: []
|