momento 0.1.0 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +3 -0
  3. data/.rubocop.yml +26 -1
  4. data/.ruby-version +1 -1
  5. data/.yardopts +2 -0
  6. data/CHANGELOG.md +119 -0
  7. data/CONTRIBUTING.md +6 -7
  8. data/Gemfile +1 -6
  9. data/Gemfile.lock +34 -24
  10. data/README.md +143 -38
  11. data/README.template.md +93 -0
  12. data/examples/.gitignore +1 -0
  13. data/examples/Gemfile +5 -0
  14. data/examples/README.md +34 -0
  15. data/examples/compact.rb +47 -0
  16. data/examples/example.rb +72 -0
  17. data/examples/file.rb +58 -0
  18. data/lib/README-generating-pb.txt +1 -1
  19. data/lib/momento/auth/credential_provider.rb +78 -0
  20. data/lib/momento/cache_client.rb +457 -0
  21. data/lib/momento/collection_ttl.rb +79 -0
  22. data/lib/momento/config/configuration.rb +16 -0
  23. data/lib/momento/config/configurations.rb +17 -0
  24. data/lib/momento/config/transport/grpc_configuration.rb +25 -0
  25. data/lib/momento/config/transport/static_transport_strategy.rb +12 -0
  26. data/lib/momento/config/transport/transport_strategy.rb +16 -0
  27. data/lib/momento/error/grpc_details.rb +38 -0
  28. data/lib/momento/error/transport_details.rb +20 -0
  29. data/lib/momento/error/types.rb +247 -0
  30. data/lib/momento/error.rb +54 -0
  31. data/lib/momento/error_builder.rb +50 -0
  32. data/lib/momento/exceptions.rb +7 -0
  33. data/lib/momento/generated/README.md +16 -0
  34. data/lib/momento/generated/auth_pb.rb +52 -0
  35. data/lib/momento/generated/auth_services_pb.rb +27 -0
  36. data/lib/momento/generated/cacheclient_pb.rb +203 -0
  37. data/lib/momento/generated/cacheclient_services_pb.rb +90 -0
  38. data/lib/momento/generated/cacheping_pb.rb +38 -0
  39. data/lib/momento/generated/cacheping_services_pb.rb +23 -0
  40. data/lib/momento/generated/cachepubsub_pb.rb +48 -0
  41. data/lib/momento/generated/cachepubsub_services_pb.rb +56 -0
  42. data/lib/momento/generated/common_pb.rb +44 -0
  43. data/lib/momento/generated/controlclient_pb.rb +72 -0
  44. data/lib/momento/generated/controlclient_services_pb.rb +35 -0
  45. data/lib/momento/generated/extensions_pb.rb +35 -0
  46. data/lib/momento/generated/generate_protos.sh +47 -0
  47. data/lib/momento/generated/leaderboard_pb.rb +56 -0
  48. data/lib/momento/generated/leaderboard_services_pb.rb +57 -0
  49. data/lib/momento/generated/permissionmessages_pb.rb +48 -0
  50. data/lib/momento/generated/token_pb.rb +43 -0
  51. data/lib/momento/generated/token_services_pb.rb +23 -0
  52. data/lib/momento/generated/webhook_pb.rb +49 -0
  53. data/lib/momento/generated/webhook_services_pb.rb +32 -0
  54. data/lib/momento/{create_cache_response.rb → response/control/create_cache_response.rb} +33 -24
  55. data/lib/momento/{delete_cache_response.rb → response/control/delete_cache_response.rb} +28 -21
  56. data/lib/momento/response/control/list_caches_response.rb +80 -0
  57. data/lib/momento/response/delete_response.rb +45 -0
  58. data/lib/momento/response/error.rb +10 -3
  59. data/lib/momento/response/get_response.rb +107 -0
  60. data/lib/momento/response/response.rb +67 -0
  61. data/lib/momento/response/response_builder.rb +18 -0
  62. data/lib/momento/response/set_response.rb +59 -0
  63. data/lib/momento/response/sort_order.rb +11 -0
  64. data/lib/momento/response/sorted_set/sorted_set_fetch_response.rb +107 -0
  65. data/lib/momento/response/sorted_set/sorted_set_put_element_response.rb +44 -0
  66. data/lib/momento/response/sorted_set/sorted_set_put_elements_response.rb +44 -0
  67. data/lib/momento/ttl.rb +48 -0
  68. data/lib/momento/version.rb +2 -1
  69. data/lib/momento.rb +6 -1
  70. data/momento.gemspec +6 -3
  71. data/release-please-config.json +15 -0
  72. data/sig/momento/auth/credential_provider.rbs +11 -0
  73. data/sig/momento/cache_client.rbs +12 -0
  74. data/sig/momento/collection_ttl.rbs +22 -0
  75. data/sig/momento/config/configuration.rbs +9 -0
  76. data/sig/momento/config/configurations.rbs +9 -0
  77. data/sig/momento/config/transport/grpc_configuration.rbs +7 -0
  78. data/sig/momento/config/transport/transport_strategy.rbs +7 -0
  79. data/sig/momento/list_caches_response.rbs +7 -0
  80. data/sig/momento/sorted_set_fetch_response.rbs +13 -0
  81. data/sig/momento/sorted_set_put_element_response.rbs +5 -0
  82. data/sig/momento/sorted_set_put_elements_response.rbs +5 -0
  83. metadata +127 -28
  84. data/examples/basic.rb +0 -45
  85. data/lib/momento/cacheclient_pb.rb +0 -332
  86. data/lib/momento/cacheclient_services_pb.rb +0 -42
  87. data/lib/momento/controlclient_pb.rb +0 -71
  88. data/lib/momento/controlclient_services_pb.rb +0 -29
  89. data/lib/momento/delete_response.rb +0 -33
  90. data/lib/momento/get_response.rb +0 -80
  91. data/lib/momento/list_caches_response.rb +0 -53
  92. data/lib/momento/response.rb +0 -17
  93. data/lib/momento/set_response.rb +0 -39
  94. data/lib/momento/simple_cache_client.rb +0 -204
data/examples/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem 'momento', '~> 0.2.0'
@@ -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
+ ```
@@ -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?
@@ -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 ::Momento::CacheClient
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