momento 0.1.0 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +26 -1
- data/.ruby-version +1 -1
- data/.yardopts +2 -0
- data/CHANGELOG.md +119 -0
- data/CONTRIBUTING.md +6 -7
- data/Gemfile +1 -6
- data/Gemfile.lock +34 -24
- data/README.md +143 -38
- data/README.template.md +93 -0
- data/examples/.gitignore +1 -0
- data/examples/Gemfile +5 -0
- data/examples/README.md +34 -0
- data/examples/compact.rb +47 -0
- data/examples/example.rb +72 -0
- data/examples/file.rb +58 -0
- data/lib/README-generating-pb.txt +1 -1
- data/lib/momento/auth/credential_provider.rb +78 -0
- data/lib/momento/cache_client.rb +457 -0
- data/lib/momento/collection_ttl.rb +79 -0
- data/lib/momento/config/configuration.rb +16 -0
- data/lib/momento/config/configurations.rb +17 -0
- data/lib/momento/config/transport/grpc_configuration.rb +25 -0
- data/lib/momento/config/transport/static_transport_strategy.rb +12 -0
- data/lib/momento/config/transport/transport_strategy.rb +16 -0
- data/lib/momento/error/grpc_details.rb +38 -0
- data/lib/momento/error/transport_details.rb +20 -0
- data/lib/momento/error/types.rb +247 -0
- data/lib/momento/error.rb +54 -0
- data/lib/momento/error_builder.rb +50 -0
- data/lib/momento/exceptions.rb +7 -0
- data/lib/momento/generated/README.md +16 -0
- data/lib/momento/generated/auth_pb.rb +52 -0
- data/lib/momento/generated/auth_services_pb.rb +27 -0
- data/lib/momento/generated/cacheclient_pb.rb +203 -0
- data/lib/momento/generated/cacheclient_services_pb.rb +90 -0
- data/lib/momento/generated/cacheping_pb.rb +38 -0
- data/lib/momento/generated/cacheping_services_pb.rb +23 -0
- data/lib/momento/generated/cachepubsub_pb.rb +48 -0
- data/lib/momento/generated/cachepubsub_services_pb.rb +56 -0
- data/lib/momento/generated/common_pb.rb +44 -0
- data/lib/momento/generated/controlclient_pb.rb +72 -0
- data/lib/momento/generated/controlclient_services_pb.rb +35 -0
- data/lib/momento/generated/extensions_pb.rb +35 -0
- data/lib/momento/generated/generate_protos.sh +47 -0
- data/lib/momento/generated/leaderboard_pb.rb +56 -0
- data/lib/momento/generated/leaderboard_services_pb.rb +57 -0
- data/lib/momento/generated/permissionmessages_pb.rb +48 -0
- data/lib/momento/generated/token_pb.rb +43 -0
- data/lib/momento/generated/token_services_pb.rb +23 -0
- data/lib/momento/generated/webhook_pb.rb +49 -0
- data/lib/momento/generated/webhook_services_pb.rb +32 -0
- data/lib/momento/{create_cache_response.rb → response/control/create_cache_response.rb} +33 -24
- data/lib/momento/{delete_cache_response.rb → response/control/delete_cache_response.rb} +28 -21
- data/lib/momento/response/control/list_caches_response.rb +80 -0
- data/lib/momento/response/delete_response.rb +45 -0
- data/lib/momento/response/error.rb +10 -3
- data/lib/momento/response/get_response.rb +107 -0
- data/lib/momento/response/response.rb +67 -0
- data/lib/momento/response/response_builder.rb +18 -0
- data/lib/momento/response/set_response.rb +59 -0
- data/lib/momento/response/sort_order.rb +11 -0
- data/lib/momento/response/sorted_set/sorted_set_fetch_response.rb +107 -0
- data/lib/momento/response/sorted_set/sorted_set_put_element_response.rb +44 -0
- data/lib/momento/response/sorted_set/sorted_set_put_elements_response.rb +44 -0
- data/lib/momento/ttl.rb +48 -0
- data/lib/momento/version.rb +2 -1
- data/lib/momento.rb +6 -1
- data/momento.gemspec +6 -3
- data/release-please-config.json +15 -0
- data/sig/momento/auth/credential_provider.rbs +11 -0
- data/sig/momento/cache_client.rbs +12 -0
- data/sig/momento/collection_ttl.rbs +22 -0
- data/sig/momento/config/configuration.rbs +9 -0
- data/sig/momento/config/configurations.rbs +9 -0
- data/sig/momento/config/transport/grpc_configuration.rbs +7 -0
- data/sig/momento/config/transport/transport_strategy.rbs +7 -0
- data/sig/momento/list_caches_response.rbs +7 -0
- data/sig/momento/sorted_set_fetch_response.rbs +13 -0
- data/sig/momento/sorted_set_put_element_response.rbs +5 -0
- data/sig/momento/sorted_set_put_elements_response.rbs +5 -0
- metadata +127 -28
- data/examples/basic.rb +0 -45
- data/lib/momento/cacheclient_pb.rb +0 -332
- data/lib/momento/cacheclient_services_pb.rb +0 -42
- data/lib/momento/controlclient_pb.rb +0 -71
- data/lib/momento/controlclient_services_pb.rb +0 -29
- data/lib/momento/delete_response.rb +0 -33
- data/lib/momento/get_response.rb +0 -80
- data/lib/momento/list_caches_response.rb +0 -53
- data/lib/momento/response.rb +0 -17
- data/lib/momento/set_response.rb +0 -39
- data/lib/momento/simple_cache_client.rb +0 -204
data/examples/Gemfile
ADDED
data/examples/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
<img src="https://docs.momentohq.com/img/logo.svg" alt="Momento logo" width="400"/>
|
2
|
+
|
3
|
+
# Momento Ruby Client Examples
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
See the [project's README](https://github.com/momentohq/client-sdk-ruby/blob/main/README.md).
|
8
|
+
|
9
|
+
## Running the examples
|
10
|
+
|
11
|
+
First, install the gem and its dependencies.
|
12
|
+
|
13
|
+
```sh
|
14
|
+
bundle
|
15
|
+
```
|
16
|
+
|
17
|
+
Then, set the required environment variables:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
export MOMENTO_API_KEY=<YOUR_API_KEY>
|
21
|
+
export MOMENTO_CACHE_NAME=<YOUR_CACHE_NAME>
|
22
|
+
```
|
23
|
+
|
24
|
+
And now you can run the example programs.
|
25
|
+
|
26
|
+
* example.rb - shows off all the basic functionality
|
27
|
+
* compact.rb - the same, written in a compact style
|
28
|
+
* file.rb - demonstrates how to cache a file
|
29
|
+
|
30
|
+
If you wish to use the version of Momento in this repository, include the lib directory when you run the examples.
|
31
|
+
|
32
|
+
```sh
|
33
|
+
ruby -I../lib example.rb
|
34
|
+
```
|
data/examples/compact.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# This does the same work as in example.rb, but demonstrates a more compact style.
|
2
|
+
|
3
|
+
require 'momento'
|
4
|
+
|
5
|
+
# Cached items will be deleted after 10 seconds.
|
6
|
+
TTL_SECONDS = 10
|
7
|
+
|
8
|
+
# The name of the cache to create *and delete*
|
9
|
+
CACHE_NAME = ENV.fetch('MOMENTO_CACHE_NAME')
|
10
|
+
|
11
|
+
# Create a credential provider that loads a Momento API Key from an environment variable.
|
12
|
+
credential_provider = Momento::CredentialProvider.from_env_var('MOMENTO_API_KEY')
|
13
|
+
|
14
|
+
# Instantiate a Momento client.
|
15
|
+
client = Momento::CacheClient.new(
|
16
|
+
configuration: Momento::Cache::Configurations::Laptop.latest,
|
17
|
+
credential_provider: credential_provider,
|
18
|
+
default_ttl: TTL_SECONDS
|
19
|
+
)
|
20
|
+
|
21
|
+
# Create a cache to play with.
|
22
|
+
# It might be created, or it might already exist.
|
23
|
+
response = client.create_cache(CACHE_NAME)
|
24
|
+
raise response.error if response.error?
|
25
|
+
|
26
|
+
# List our caches.
|
27
|
+
response = client.list_caches
|
28
|
+
raise response.error if response.error?
|
29
|
+
|
30
|
+
puts "Caches: #{response.cache_names&.join(", ")}"
|
31
|
+
|
32
|
+
# Put an item in the cache.
|
33
|
+
response = client.set(CACHE_NAME, "key", "You cached something!")
|
34
|
+
raise response.error if response.error?
|
35
|
+
|
36
|
+
# And get it back.
|
37
|
+
response = client.get(CACHE_NAME, "key")
|
38
|
+
puts response.value_string || "The item wasn't found in the cache."
|
39
|
+
raise response.error if response.error?
|
40
|
+
|
41
|
+
# Now delete it.
|
42
|
+
response = client.delete(CACHE_NAME, "key")
|
43
|
+
raise response.error if response.error?
|
44
|
+
|
45
|
+
# And delete our test cache.
|
46
|
+
response = client.delete_cache(CACHE_NAME)
|
47
|
+
raise response.error if response.error?
|
data/examples/example.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# An example of the basic functionality of
|
2
|
+
# Momento::CacheClient.
|
3
|
+
|
4
|
+
require 'momento'
|
5
|
+
|
6
|
+
# Cached items will be deleted after 12.5 seconds.
|
7
|
+
TTL_SECONDS = 12.5
|
8
|
+
|
9
|
+
# The name of the cache to create *and delete*
|
10
|
+
CACHE_NAME = ENV.fetch('MOMENTO_CACHE_NAME')
|
11
|
+
|
12
|
+
# Create a credential provider that loads a Momento API Key from an environment variable.
|
13
|
+
credential_provider = Momento::CredentialProvider.from_env_var('MOMENTO_API_KEY')
|
14
|
+
|
15
|
+
# Instantiate a Momento client.
|
16
|
+
client = Momento::CacheClient.new(
|
17
|
+
configuration: Momento::Cache::Configurations::Laptop.latest,
|
18
|
+
credential_provider: credential_provider,
|
19
|
+
default_ttl: TTL_SECONDS
|
20
|
+
)
|
21
|
+
|
22
|
+
# Create a cache to play with.
|
23
|
+
response = client.create_cache(CACHE_NAME)
|
24
|
+
if response.success?
|
25
|
+
puts "Created the cache."
|
26
|
+
elsif response.already_exists?
|
27
|
+
puts "Cache already exists."
|
28
|
+
elsif response.error?
|
29
|
+
raise "Couldn't create a cache: #{response.error}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# List our caches.
|
33
|
+
response = client.list_caches
|
34
|
+
if response.success?
|
35
|
+
puts "Caches: #{response.cache_names&.join(", ")}"
|
36
|
+
elsif response.error?
|
37
|
+
raise "Couldn't list the caches: #{response.error}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Put an item in the cache.
|
41
|
+
response = client.set(CACHE_NAME, "key", "You cached something!")
|
42
|
+
if response.success?
|
43
|
+
puts "Set an item in the cache."
|
44
|
+
elsif response.error?
|
45
|
+
raise "Couldn't set an item in the cache: #{response.error}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# And get it back.
|
49
|
+
response = client.get(CACHE_NAME, "key")
|
50
|
+
if response.hit?
|
51
|
+
puts "Cache returned: #{response.value_string}"
|
52
|
+
elsif response.miss?
|
53
|
+
puts "The item wasn't found in the cache."
|
54
|
+
elsif response.error?
|
55
|
+
raise "Couldn't get an item from the cache: #{response.error}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Now delete it.
|
59
|
+
response = client.delete(CACHE_NAME, "key")
|
60
|
+
if response.success?
|
61
|
+
puts "Key/value deleted."
|
62
|
+
elsif response.error?
|
63
|
+
raise "Couldn't delete an item from the cache: #{response.error}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# And delete our test cache.
|
67
|
+
response = client.delete_cache(CACHE_NAME)
|
68
|
+
if response.success?
|
69
|
+
puts "Deleted the cache."
|
70
|
+
elsif response.error?
|
71
|
+
raise "Couldn't create a cache: #{response.error}"
|
72
|
+
end
|
data/examples/file.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# This is an example of storing binary data.
|
2
|
+
#
|
3
|
+
# It will cache a test image, read it back,
|
4
|
+
# and write it to disk as test_copy.jpg.
|
5
|
+
|
6
|
+
require 'momento'
|
7
|
+
|
8
|
+
# Cached items will be deleted after 12.5 seconds.
|
9
|
+
TTL_SECONDS = 12.5
|
10
|
+
|
11
|
+
# The name of the cache to create *and delete*
|
12
|
+
CACHE_NAME = ENV.fetch('MOMENTO_CACHE_NAME')
|
13
|
+
|
14
|
+
# So it can be run from the top of the repo
|
15
|
+
# or from the examples directory.
|
16
|
+
FILE_LOCATIONS = [
|
17
|
+
"spec/support/assets/test.jpg",
|
18
|
+
"../spec/support/assets/test.jpg"
|
19
|
+
].freeze
|
20
|
+
|
21
|
+
# Create a credential provider that loads a Momento API Key from an environment variable.
|
22
|
+
credential_provider = Momento::CredentialProvider.from_env_var('MOMENTO_API_KEY')
|
23
|
+
|
24
|
+
# Instantiate a Momento client.
|
25
|
+
client = Momento::CacheClient.new(
|
26
|
+
configuration: Momento::Cache::Configurations::Laptop.latest,
|
27
|
+
credential_provider: credential_provider,
|
28
|
+
default_ttl: TTL_SECONDS
|
29
|
+
)
|
30
|
+
|
31
|
+
# Create a cache for testing, or use an already existing one.
|
32
|
+
response = client.create_cache(CACHE_NAME)
|
33
|
+
raise response.error if response.error?
|
34
|
+
|
35
|
+
# Read an image file.
|
36
|
+
file = FILE_LOCATIONS.find { |f| File.exist?(f) }
|
37
|
+
contents = File.read(file)
|
38
|
+
|
39
|
+
# Add the image to the cache.
|
40
|
+
puts "Caching #{file}"
|
41
|
+
client.set(CACHE_NAME, "test.jpg", contents)
|
42
|
+
raise response.error if response.error?
|
43
|
+
|
44
|
+
puts "Retrieving the image"
|
45
|
+
response = client.get(CACHE_NAME, "test.jpg")
|
46
|
+
raise "Cache image was not found!" if response.miss?
|
47
|
+
raise response.error if response.error?
|
48
|
+
|
49
|
+
puts "Writing the image as test_copy.jpg"
|
50
|
+
f = File.open("test_copy.jpg", "wb")
|
51
|
+
f.write(response.value_bytes)
|
52
|
+
f.close
|
53
|
+
|
54
|
+
# Delete our test cache.
|
55
|
+
response = client.delete_cache(CACHE_NAME)
|
56
|
+
raise response.error if response.error?
|
57
|
+
|
58
|
+
puts "Now open test_copy.jpg"
|
@@ -25,4 +25,4 @@ Put them in their own namespace.
|
|
25
25
|
1. Wrap the modules in `module Momento`.
|
26
26
|
2. In the *_services_pb.rb files, change the module names.
|
27
27
|
* rename ::ControlClient to ::Momento::ControlClient
|
28
|
-
* rename ::CacheClient to ::
|
28
|
+
* rename ::CacheClient to ::MomentoProtos::CacheClient
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Momento
|
5
|
+
# Contains the information required for a Momento client to connect to and authenticate with Momento services.
|
6
|
+
class CredentialProvider
|
7
|
+
attr_reader :api_key, :control_endpoint, :cache_endpoint
|
8
|
+
|
9
|
+
# Creates a CredentialProvider from a Momento API key loaded from an environment variable.
|
10
|
+
# @param env_var_name [String] the environment variable containing the API key
|
11
|
+
# @return [Momento::CredentialProvider]
|
12
|
+
# @raise [Momento::Error::InvalidArgumentError] if the API key is invalid
|
13
|
+
def self.from_env_var(env_var_name)
|
14
|
+
api_key = ENV.fetch(env_var_name) {
|
15
|
+
raise Momento::Error::InvalidArgumentError, "Env var #{env_var_name} must be set"
|
16
|
+
}
|
17
|
+
new(api_key)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates a CredentialProvider from a Momento API key
|
21
|
+
# @param api_key [String] the Momento API key
|
22
|
+
# @return [Momento::CredentialProvider]
|
23
|
+
# @raise [Momento::Error::InvalidArgumentError] if the API key is invalid
|
24
|
+
def self.from_string(api_key)
|
25
|
+
raise Momento::Error::InvalidArgumentError, 'Auth token string cannot be empty' if api_key.empty?
|
26
|
+
|
27
|
+
new(api_key)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def initialize(api_key)
|
33
|
+
decoded_token = decode_api_key(api_key)
|
34
|
+
@api_key = decoded_token.api_key
|
35
|
+
@control_endpoint = decoded_token.control_endpoint
|
36
|
+
@cache_endpoint = decoded_token.cache_endpoint
|
37
|
+
rescue StandardError => e
|
38
|
+
raise Momento::Error::InvalidArgumentError, e.message
|
39
|
+
end
|
40
|
+
|
41
|
+
AuthTokenData = Struct.new(:api_key, :cache_endpoint, :control_endpoint)
|
42
|
+
|
43
|
+
def decode_api_key(api_key)
|
44
|
+
decode_v1_key(api_key)
|
45
|
+
rescue StandardError
|
46
|
+
decode_legacy_key(api_key)
|
47
|
+
end
|
48
|
+
|
49
|
+
def decode_legacy_key(api_key)
|
50
|
+
key_parts = api_key.split('.')
|
51
|
+
raise Momento::Error::InvalidArgumentError, 'Malformed legacy API key' if key_parts.size != 3
|
52
|
+
|
53
|
+
decoded_key = Base64.decode64(key_parts[1])
|
54
|
+
key_json = JSON.parse(decoded_key, symbolize_names: true)
|
55
|
+
validate_key_json(key_json, %i[c cp])
|
56
|
+
|
57
|
+
AuthTokenData.new(api_key, key_json[:c], key_json[:cp])
|
58
|
+
end
|
59
|
+
|
60
|
+
def decode_v1_key(api_key)
|
61
|
+
decoded_key = Base64.decode64(api_key)
|
62
|
+
key_json = JSON.parse(decoded_key, symbolize_names: true)
|
63
|
+
validate_key_json(key_json, %i[api_key endpoint])
|
64
|
+
|
65
|
+
AuthTokenData.new(key_json[:api_key], "cache.#{key_json[:endpoint]}", "control.#{key_json[:endpoint]}")
|
66
|
+
rescue StandardError
|
67
|
+
raise Momento::Error::InvalidArgumentError, 'Malformed Momento API Key'
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_key_json(key_json, required_fields)
|
71
|
+
missing_fields = required_fields.reject { |field| key_json.key?(field) }
|
72
|
+
return if missing_fields.empty?
|
73
|
+
|
74
|
+
raise Momento::Error::InvalidArgumentError,
|
75
|
+
"Required fields are missing: #{missing_fields.join(', ')}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|