google-gax 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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