google-gax 0.1.1

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.
@@ -0,0 +1,51 @@
1
+ # Copyright 2016, Google Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are
6
+ # met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above
11
+ # copyright notice, this list of conditions and the following disclaimer
12
+ # in the documentation and/or other materials provided with the
13
+ # distribution.
14
+ # * Neither the name of Google Inc. nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ module Google
31
+ module Gax
32
+ # Common base class for exceptions raised by GAX.
33
+ class GaxError < StandardError
34
+ attr_reader :cause
35
+
36
+ # @param msg [String] describes the error that occurred.
37
+ # @param cause [Error] the exception raised by a lower layer of
38
+ # the RPC stack (for example, gRPC) that caused this
39
+ # exception, or None if this exception originated in GAX.
40
+ def initialize(msg, cause:nil)
41
+ msg = "GaxError #{msg}, caused by #{cause}" if cause
42
+ super(msg)
43
+ @cause = cause
44
+ end
45
+ end
46
+
47
+ # Indicates an error during automatic GAX retrying.
48
+ class RetryError < GaxError
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,94 @@
1
+ # Copyright 2016, Google Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are
6
+ # met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above
11
+ # copyright notice, this list of conditions and the following disclaimer
12
+ # in the documentation and/or other materials provided with the
13
+ # distribution.
14
+ # * Neither the name of Google Inc. nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'grpc'
31
+ require 'googleauth'
32
+
33
+ module Google
34
+ module Gax
35
+ # Grpc adapts the gRPC surface
36
+ module Grpc
37
+ STATUS_CODE_NAMES = GRPC::Core::StatusCodes.constants.map do |sym|
38
+ [sym.to_s, GRPC::Core::StatusCodes.const_get(sym)]
39
+ end.to_h.freeze
40
+
41
+ API_ERRORS = [GRPC::BadStatus, GRPC::Cancelled].freeze
42
+
43
+ # rubocop:disable Metrics/ParameterLists
44
+
45
+ # Creates a gRPC client stub.
46
+ #
47
+ # @param service_path [String] The domain name of the API remote host.
48
+ #
49
+ # @param port [Fixnum] The port on which to connect to the remote host.
50
+ #
51
+ # @param chan_creds [Object] A ClientCredentials object for use with an
52
+ # SSL-enabled Channel. If none, credentials are pulled from a default
53
+ # location.
54
+ #
55
+ # @param channel [Object] A Channel object through which to make calls. If
56
+ # none, a secure channel is constructed.
57
+ #
58
+ # @param updater_proc [Proc]
59
+ # A function that transforms the metadata for requests, e.g., to give
60
+ # OAuth credentials.
61
+ #
62
+ # @param scopes [Array<String>]
63
+ # The OAuth scopes for this service. This parameter is ignored if
64
+ # a custom metadata_transformer is supplied.
65
+ #
66
+ # @yield [address, creds]
67
+ # the generated gRPC method to create a stub.
68
+ #
69
+ # @return A gRPC client stub.
70
+ def create_stub(service_path,
71
+ port,
72
+ chan_creds: nil,
73
+ channel: nil,
74
+ updater_proc: nil,
75
+ scopes: nil)
76
+ address = "#{service_path}:#{port}"
77
+ if channel.nil?
78
+ chan_creds = GRPC::Core::ChannelCredentials.new if chan_creds.nil?
79
+ if updater_proc.nil?
80
+ auth_creds = Google::Auth.get_application_default(scopes)
81
+ updater_proc = auth_creds.updater_proc
82
+ end
83
+ call_creds = GRPC::Core::CallCredentials.new(updater_proc)
84
+ chan_creds = chan_creds.compose(call_creds)
85
+ yield(address, chan_creds)
86
+ else
87
+ yield(address, nil, channel_override: channel)
88
+ end
89
+ end
90
+
91
+ module_function :create_stub
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,248 @@
1
+ # Copyright 2016, Google Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are
6
+ # met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above
11
+ # copyright notice, this list of conditions and the following disclaimer
12
+ # in the documentation and/or other materials provided with the
13
+ # distribution.
14
+ # * Neither the name of Google Inc. nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'rly'
31
+
32
+ module Google
33
+ # Gax defines Google API extensions
34
+ module Gax
35
+ # Lexer for the path_template language
36
+ class PathLex < Rly::Lex
37
+ token :FORWARD_SLASH, %r{/}
38
+ token :LEFT_BRACE, /\{/
39
+ token :RIGHT_BRACE, /\}/
40
+ token :EQUALS, /=/
41
+ token :PATH_WILDCARD, /\*\*/ # has to occur before WILDCARD
42
+ token :WILDCARD, /\*/
43
+ token :LITERAL, %r{[^*=\}\{\/ ]+}
44
+
45
+ on_error do |t|
46
+ raise t ? "Syntax error at '#{t.value}'" : 'Syntax error at EOF'
47
+ end
48
+ end
49
+
50
+ # Parser for the path_template language
51
+ class PathParse < Rly::Yacc
52
+ attr_reader :segment_count, :binding_var_count
53
+
54
+ def initialize(*args)
55
+ super
56
+ @segment_count = 0
57
+ @binding_var_count = 0
58
+ end
59
+
60
+ def parse(*args)
61
+ segments = super
62
+ has_path_wildcard = false
63
+ raise 'path template has no segments' if segments.nil?
64
+ segments.each do |s|
65
+ next unless s.kind == TERMINAL && s.literal == '**'
66
+ if has_path_wildcard
67
+ raise 'path template cannot contain more than one path wildcard'
68
+ else
69
+ has_path_wildcard = true
70
+ end
71
+ end
72
+ segments
73
+ end
74
+
75
+ rule 'template : FORWARD_SLASH bound_segments
76
+ | bound_segments' do |template, *segments|
77
+ template.value = segments[-1].value
78
+ end
79
+
80
+ rule 'bound_segments : bound_segment FORWARD_SLASH bound_segments
81
+ | bound_segment' do |segs, a_seg, _, more_segs|
82
+ segs.value = a_seg.value
83
+ segs.value.push(*more_segs.value) unless more_segs.nil?
84
+ end
85
+
86
+ rule 'unbound_segments : unbound_terminal FORWARD_SLASH unbound_segments
87
+ | unbound_terminal' do |segs, a_term, _, more_segs|
88
+ segs.value = a_term.value
89
+ segs.value.push(*more_segs.value) unless more_segs.nil?
90
+ end
91
+
92
+ rule 'bound_segment : bound_terminal
93
+ | variable' do |segment, term_or_var|
94
+ segment.value = term_or_var.value
95
+ end
96
+
97
+ rule 'unbound_terminal : WILDCARD
98
+ | PATH_WILDCARD
99
+ | LITERAL' do |term, literal|
100
+ term.value = [Segment.new(TERMINAL, literal.value)]
101
+ @segment_count += 1
102
+ end
103
+
104
+ rule 'bound_terminal : unbound_terminal' do |bound, unbound|
105
+ if ['*', '**'].include?(unbound.value[0].literal)
106
+ bound.value = [
107
+ Segment.new(BINDING, format('$%d', @binding_var_count)),
108
+ unbound.value[0],
109
+ Segment.new(END_BINDING, '')
110
+ ]
111
+ @binding_var_count += 1
112
+ else
113
+ bound.value = unbound.value
114
+ end
115
+ end
116
+
117
+ rule 'variable : LEFT_BRACE LITERAL EQUALS unbound_segments RIGHT_BRACE
118
+ | LEFT_BRACE LITERAL RIGHT_BRACE' do |variable, *args|
119
+ variable.value = [Segment.new(BINDING, args[1].value)]
120
+ if args.size > 3
121
+ variable.value.push(*args[3].value)
122
+ else
123
+ variable.value.push(Segment.new(TERMINAL, '*'))
124
+ @segment_count += 1
125
+ end
126
+ variable.value.push(Segment.new(END_BINDING, ''))
127
+ end
128
+ end
129
+
130
+ # PathTemplate parses and format resource names
131
+ class PathTemplate
132
+ attr_reader :segments, :size
133
+
134
+ def initialize(data)
135
+ parser = PathParse.new(PathLex.new)
136
+ @segments = parser.parse(data)
137
+ @size = parser.segment_count
138
+ end
139
+
140
+ # Formats segments as a string.
141
+ #
142
+ # @param [Array<Segments>]
143
+ # The segments to be formatted
144
+ # @return [String] the formatted output
145
+ def self.format_segments(*segments)
146
+ template = ''
147
+ slash = true
148
+ segments.each do |segment|
149
+ if segment.kind == TERMINAL
150
+ template += '/' if slash
151
+ template += segment.literal.to_s
152
+ next
153
+ end
154
+ slash = true
155
+ if segment.kind == BINDING
156
+ template += "/{#{segment.literal}="
157
+ slash = false
158
+ else
159
+ template += "#{segment.literal}}"
160
+ end
161
+ end
162
+ template[1, template.length] # exclude the initial slash
163
+ end
164
+
165
+ # Renders a path template using the provided bindings.
166
+ # @param binding [Hash]
167
+ # A mapping of var names to binding strings.
168
+ # @return [String] A rendered representation of this path template.
169
+ # @raise [ArgumentError] If a key isn't provided or if a sub-template
170
+ # can't be parsed.
171
+ def render(**bindings)
172
+ out = []
173
+ binding = false
174
+ @segments.each do |segment|
175
+ if segment.kind == BINDING
176
+ literal_sym = segment.literal.to_sym
177
+ unless bindings.key?(literal_sym)
178
+ msg = "Value for key #{segment.literal} is not provided"
179
+ raise(ArgumentError, msg)
180
+ end
181
+ out.push(*PathTemplate.new(bindings[literal_sym]).segments)
182
+ binding = true
183
+ elsif segment.kind == END_BINDING
184
+ binding = false
185
+ else
186
+ next if binding
187
+ out << segment
188
+ end
189
+ end
190
+ path = self.class.format_segments(*out)
191
+ match(path)
192
+ path
193
+ end
194
+
195
+ # Matches a fully qualified path template string.
196
+ # @param path [String]
197
+ # A fully qualified path template string.
198
+ # @return [Hash] Var names to matched binding values.
199
+ # @raise [ArgumentError] If path can't be matched to the template.
200
+ def match(path)
201
+ that = path.split('/')
202
+ current_var = nil
203
+ bindings = {}
204
+ segment_count = @size
205
+ i = 0
206
+ @segments.each do |segment|
207
+ break if i >= that.size
208
+ if segment.kind == TERMINAL
209
+ if segment.literal == '*'
210
+ bindings[current_var] = that[i]
211
+ i += 1
212
+ elsif segment.literal == '**'
213
+ size = that.size - segment_count + 1
214
+ segment_count += size - 1
215
+ bindings[current_var] = that[i, size].join('/')
216
+ i += size
217
+ elsif segment.literal != that[i]
218
+ throw ArgumentError.new(
219
+ "mismatched literal: '#{segment.literal}' != '#{that[i]}'")
220
+ else
221
+ i += 1
222
+ end
223
+ elsif segment.kind == BINDING
224
+ current_var = segment.literal
225
+ end
226
+ end
227
+ if i != that.size || i != segment_count
228
+ throw ArgumentError.new(
229
+ "match error: could not instantiate a path template from #{path}")
230
+ end
231
+ bindings
232
+ end
233
+
234
+ def to_s
235
+ self.class.format_segments(*@segments)
236
+ end
237
+ end
238
+
239
+ Segment = Struct.new(:kind, :literal)
240
+
241
+ # Private constants/methods/classes
242
+ BINDING = 1
243
+ END_BINDING = 2
244
+ TERMINAL = 3
245
+
246
+ private_constant :BINDING, :END_BINDING, :TERMINAL
247
+ end
248
+ end
@@ -0,0 +1,213 @@
1
+ # Copyright 2016, Google Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are
6
+ # met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above
11
+ # copyright notice, this list of conditions and the following disclaimer
12
+ # in the documentation and/or other materials provided with the
13
+ # distribution.
14
+ # * Neither the name of Google Inc. nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ module Google
31
+ module Gax
32
+ # Helper for #construct_settings
33
+ #
34
+ # @param method_config A dictionary representing a single
35
+ # ``methods`` entry of the standard API client config file. (See
36
+ # #construct_settings for information on this yaml.)
37
+ # @param method_retry_override [BundleOptions, :OPTION_INHERIT, nil]
38
+ # If set to :OPTION_INHERIT, the retry settings are derived from
39
+ # method config. Otherwise, this parameter overrides
40
+ # +method_config+.
41
+
42
+ # @param bundle_descriptor [BundleDescriptor] A BundleDescriptor
43
+ # object describing the structure of bundling for this
44
+ # method. If not set, this method will not bundle.
45
+ # @return An Executor that configures bundling, or nil if this
46
+ # method should not bundle.
47
+ def _construct_bundling(method_config, method_bundling_override,
48
+ bundle_descriptor)
49
+ if method_config.key?('bundling') && bundle_descriptor
50
+ if method_bundling_override == :OPTION_INHERIT
51
+ options = BundleOptions.new
52
+ method_config['bundling'].each_pair do |key, value|
53
+ options[key.intern] = value
54
+ end
55
+ # TODO: comment-out when bundling is supported.
56
+ # Executor.new(options)
57
+ elsif method_bundling_override
58
+ # Executor.new(method_bundling_override)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Helper for #construct_settings
64
+ #
65
+ # @param method_config [Hash] A dictionary representing a single
66
+ # +methods+ entry of the standard API client config file. (See
67
+ # #construct_settings for information on this yaml.)
68
+ # @param method_retry_override [RetryOptions, :OPTION_INHERIT, nil]
69
+ # If set to :OPTION_INHERIT, the retry settings are derived from
70
+ # method config. Otherwise, this parameter overrides
71
+ # +method_config+.
72
+ # @param retry_codes_def [Hash] A dictionary parsed from the
73
+ # +retry_codes_def+ entry of the standard API client config
74
+ # file. (See #construct_settings for information on this yaml.)
75
+ # @param retry_params [Hash] A dictionary parsed from the
76
+ # +retry_params+ entry of the standard API client config
77
+ # file. (See #construct_settings for information on this yaml.)
78
+ # @param retry_names [Hash] A dictionary mapping the string names
79
+ # used in the standard API client config file to API response
80
+ # status codes.
81
+ # @return [RetryOptions, nil]
82
+ def _construct_retry(method_config, method_retry_override, retry_codes,
83
+ retry_params, retry_names)
84
+ unless method_retry_override == :OPTION_INHERIT
85
+ return method_retry_override
86
+ end
87
+
88
+ retry_codes ||= {}
89
+ retry_codes_name = method_config['retry_codes_name']
90
+ codes = retry_codes.fetch(retry_codes_name, []).map do |name|
91
+ retry_names[name]
92
+ end
93
+
94
+ if retry_params && method_config.key?('retry_params_name')
95
+ params = retry_params[method_config['retry_params_name']]
96
+ backoff_settings = BackoffSettings.new(
97
+ *params.values_at(*BackoffSettings.members.map(&:to_s)))
98
+ end
99
+
100
+ RetryOptions.new(codes, backoff_settings)
101
+ end
102
+
103
+ def _upper_camel_to_lower_underscore(string)
104
+ string.scan(/[[:upper:]][^[:upper:]]*/).map(&:downcase).join('_')
105
+ end
106
+
107
+ # rubocop:disable Metrics/ParameterLists
108
+
109
+ # Constructs a dictionary mapping method names to CallSettings.
110
+ #
111
+ # The +client_config+ parameter is parsed from a client configuration JSON
112
+ # file of the form:
113
+ #
114
+ # {
115
+ # "interfaces": {
116
+ # "google.fake.v1.ServiceName": {
117
+ # "retry_codes": {
118
+ # "idempotent": ["UNAVAILABLE", "DEADLINE_EXCEEDED"],
119
+ # "non_idempotent": []
120
+ # },
121
+ # "retry_params": {
122
+ # "default": {
123
+ # "initial_retry_delay_millis": 100,
124
+ # "retry_delay_multiplier": 1.2,
125
+ # "max_retry_delay_millis": 1000,
126
+ # "initial_rpc_timeout_millis": 2000,
127
+ # "rpc_timeout_multiplier": 1.5,
128
+ # "max_rpc_timeout_millis": 30000,
129
+ # "total_timeout_millis": 45000
130
+ # }
131
+ # },
132
+ # "methods": {
133
+ # "CreateFoo": {
134
+ # "retry_codes_name": "idempotent",
135
+ # "retry_params_name": "default"
136
+ # },
137
+ # "Publish": {
138
+ # "retry_codes_name": "non_idempotent",
139
+ # "retry_params_name": "default",
140
+ # "bundling": {
141
+ # "element_count_threshold": 40,
142
+ # "element_count_limit": 200,
143
+ # "request_byte_threshold": 90000,
144
+ # "request_byte_limit": 100000,
145
+ # "delay_threshold_millis": 100
146
+ # }
147
+ # }
148
+ # }
149
+ # }
150
+ # }
151
+ # }
152
+ #
153
+ # @param service_name [String] The fully-qualified name of this
154
+ # service, used as a key into the client config file (in the
155
+ # example above, this value should be
156
+ # 'google.fake.v1.ServiceName').
157
+ # @param client_config [Hash] A dictionary parsed from the
158
+ # standard API client config file.
159
+ # @param bundling_override [Hash] A dictionary of method names to
160
+ # BundleOptions override those specified in +client_config+.
161
+ # @param retry_override [Hash] A dictionary of method names to
162
+ # RetryOptions that override those specified in +client_config+.
163
+ # @param retry_names [Hash] A dictionary mapping the strings
164
+ # referring to response status codes to the Python objects
165
+ # representing those codes.
166
+ # @param timeout [Numeric] The timeout parameter for all API calls
167
+ # in this dictionary.
168
+ # @param bundle_descriptors [Hash{String => BundleDescriptor}]
169
+ # A dictionary of method names to BundleDescriptor objects for
170
+ # methods that are bundling-enabled.
171
+ # @param page_descriptors [Hash{String => PageDescriptor}] A
172
+ # dictionary of method names to PageDescriptor objects for
173
+ # methods that are page streaming-enabled.
174
+ # @return [CallSettings, nil] A CallSettings, or nil if the
175
+ # service is not found in the config.
176
+ def construct_settings(
177
+ service_name, client_config, bundling_override, retry_override,
178
+ retry_names, timeout, bundle_descriptors: {}, page_descriptors: {})
179
+ defaults = {}
180
+
181
+ service_config = client_config.fetch('interfaces', {})[service_name]
182
+ return nil unless service_config
183
+
184
+ service_config['methods'].each_pair do |method_name, method_config|
185
+ snake_name = _upper_camel_to_lower_underscore(method_name)
186
+
187
+ bundle_descriptor = bundle_descriptors[snake_name]
188
+
189
+ defaults[snake_name] = CallSettings.new(
190
+ timeout: timeout,
191
+ retry_options: _construct_retry(
192
+ method_config,
193
+ retry_override.fetch(snake_name, :OPTION_INHERIT),
194
+ service_config['retry_codes'],
195
+ service_config['retry_params'],
196
+ retry_names),
197
+ page_descriptor: page_descriptors[snake_name],
198
+ bundler: _construct_bundling(
199
+ method_config,
200
+ bundling_override.fetch(snake_name, :OPTION_INHERIT),
201
+ bundle_descriptor),
202
+ bundle_descriptor: bundle_descriptor)
203
+ end
204
+
205
+ defaults
206
+ end
207
+
208
+ module_function :construct_settings, :_construct_bundling,
209
+ :_construct_retry, :_upper_camel_to_lower_underscore
210
+ private_class_method :_construct_bundling, :_construct_retry,
211
+ :_upper_camel_to_lower_underscore
212
+ end
213
+ end