gapic-common-1.2.0/0000755000004100000410000000000015143460047014117 5ustar www-datawww-datagapic-common-1.2.0/CONTRIBUTING.md0000644000004100000410000000211315143460047016345 0ustar www-datawww-data# How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to https://cla.developers.google.com/ to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). gapic-common-1.2.0/lib/0000755000004100000410000000000015143460047014665 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/0000755000004100000410000000000015143460047015750 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/rest/0000755000004100000410000000000015143460047016725 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/rest/faraday_middleware.rb0000644000004100000410000000505615143460047023064 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "faraday" module Gapic module Rest # Registers the middleware with Faraday module FaradayMiddleware ## # @private # Request middleware that constructs the Authorization HTTP header # using ::Google::Auth::Credentials # class GoogleAuthorization < Faraday::Middleware ## # @private # @param app [#call] # @param credentials [Google::Auth::Credentials, Signet::OAuth2::Client, Symbol, Proc] # Provides the means for authenticating requests made by # the client. This parameter can be many types: # * A `Google::Auth::Credentials` uses a the properties of its represented keyfile for authenticating requests # made by this client. # * A `Signet::OAuth2::Client` object used to apply the OAuth credentials. # * A `Proc` will be used as an updater_proc for the auth token. # * A `Symbol` is treated as a signal that authentication is not required. # def initialize app, credentials @updater_proc = case credentials when Symbol credentials else updater_proc = credentials.updater_proc if credentials.respond_to? :updater_proc updater_proc ||= credentials if credentials.is_a? Proc raise ArgumentError, "invalid credentials (#{credentials.class})" if updater_proc.nil? updater_proc end super app end # @private # @param env [Faraday::Env] def call env unless @updater_proc.is_a? Symbol auth_hash = @updater_proc.call({}) env.request_headers["Authorization"] = auth_hash[:authorization] end @app.call env end end Faraday::Request.register_middleware google_authorization: -> { GoogleAuthorization } end end end gapic-common-1.2.0/lib/gapic/rest/error.rb0000644000004100000410000002035315143460047020406 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "json" require "gapic/common/error" require "google/protobuf/well_known_types" # Not technically required but GRPC counterpart loads it and so should we for test parity require "google/rpc/error_details_pb" module Gapic module Rest # Gapic REST exception class class Error < ::Gapic::Common::Error # @return [Integer, nil] the http status code for the error attr_reader :status_code # @return [Object, nil] the text representation of status as parsed from the response body attr_reader :status # @return [Object, nil] the details as parsed from the response body attr_reader :details # The Cloud error wrapper expect to see a `status_details` property alias status_details details # @return [Object, nil] the headers of the REST error attr_reader :headers # The Cloud error wrapper expect to see a `header` property alias header headers ## # @param message [String, nil] error message # @param status_code [Integer, nil] HTTP status code of this error # @param status [String, nil] The text representation of status as parsed from the response body # @param details [Object, nil] Details data of this error # @param headers [Object, nil] Http headers data of this error # def initialize message, status_code, status: nil, details: nil, headers: nil super message @status_code = status_code @status = status @details = details @headers = headers end class << self ## # This creates a new error message wrapping the Faraday's one. Additionally # it tries to parse and set a detailed message and an error code from # from the Google Cloud's response body # # @param err [Faraday::Error] the Faraday error to wrap # # @return [ Gapic::Rest::Error] def wrap_faraday_error err message, status_code, status, details, headers = parse_faraday_error err Gapic::Rest::Error.new message, status_code, status: status, details: details, headers: headers end ## # @private # Tries to get the error information from Faraday error # # @param err [Faraday::Error] the Faraday error to extract information from # @return [Array(String, String, String, String, String)] def parse_faraday_error err message = err.message status_code = err.response_status status = nil details = nil headers = err.response_headers if err.response_body msg, code, status, details = try_parse_from_body err.response_body message = "An error has occurred when making a REST request: #{msg}" unless msg.nil? status_code = code unless code.nil? end [message, status_code, status, details, headers] end private ## # @private # Tries to get the error information from the JSON bodies # # @param body_str [String] # @return [Array(String, String, String, String)] def try_parse_from_body body_str body = JSON.parse body_str unless body.is_a?(::Hash) && body&.key?("error") && body["error"].is_a?(::Hash) return [nil, nil, nil, nil] end error = body["error"] message = error["message"] if error.key? "message" code = error["code"] if error.key? "code" status = error["status"] if error.key? "status" details = parse_details error["details"] if error.key? "details" [message, code, status, details] rescue JSON::ParserError [nil, nil, nil, nil] end ## # @private # Parses the details data, trying to extract the Protobuf.Any objects # from it, if it's an array of hashes. Otherwise returns it as is. # # @param details [Object, nil] the details object # # @return [Object, nil] def parse_details details # For rest errors details will contain json representations of `Protobuf.Any` # decoded into hashes. If it's not an array, of its elements are not hashes, # it's some other case return details unless details.is_a? ::Array details.map do |detail_instance| next detail_instance unless detail_instance.is_a? ::Hash # Next, parse detail_instance into a Proto message. # There are three possible issues for the JSON->Any->message parsing # - json decoding fails # - the json belongs to a proto message type we don't know about # - any unpacking fails # If we hit any of these three issues we'll just return the original hash begin any = ::Google::Protobuf::Any.decode_json detail_instance.to_json klass = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(any.type_name)&.msgclass next detail_instance if klass.nil? unpack = any.unpack klass next detail_instance if unpack.nil? unpack rescue ::Google::Protobuf::ParseError detail_instance end end.compact end end end ## # An error class that represents DeadlineExceeded error for Rest # with an optional retry root cause. # # If the deadline for making a call was exceeded during the rest calls, # this exception is thrown wrapping Faraday::TimeoutError. # # If there were other exceptions retried before that, the last one will be # saved as a "root_cause". # # @!attribute [r] root_cause # @return [Object, nil] The exception that was being retried # when the Faraday::TimeoutError error occured. # class DeadlineExceededError < Error attr_reader :root_cause ## # @private # @param message [String, nil] error message # @param status_code [Integer, nil] HTTP status code of this error # @param status [String, nil] The text representation of status as parsed from the response body # @param details [Object, nil] Details data of this error # @param headers [Object, nil] Http headers data of this error # @param root_cause [Object, nil] The exception that was being retried # when the Faraday::TimeoutError occured. # def initialize message, status_code, status: nil, details: nil, headers: nil, root_cause: nil super message, status_code, status: status, details: details, headers: headers @root_cause = root_cause end class << self ## # @private # This creates a new error message wrapping the Faraday's one. Additionally # it tries to parse and set a detailed message and an error code from # from the Google Cloud's response body # # @param err [Faraday::TimeoutError] the Faraday error to wrap # # @param root_cause [Object, nil] The exception that was being retried # when the Faraday::TimeoutError occured. # # @return [ Gapic::Rest::DeadlineExceededError] def wrap_faraday_error err, root_cause: nil message, status_code, status, details, headers = parse_faraday_error err Gapic::Rest::DeadlineExceededError.new message, status_code, status: status, details: details, headers: headers, root_cause: root_cause end end end end end gapic-common-1.2.0/lib/gapic/rest/threaded_enumerator.rb0000644000004100000410000000362115143460047023275 0ustar www-datawww-data# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Rest ## # @private # A class to provide the Enumerable interface to an incoming stream of data. # # ThreadedEnumerator provides the enumerations over the individual chunks of data received from the server. # # @example normal iteration over resources. # chunk = threaded_enumerator.next # # @attribute [r] in_q # @return [Queue] Input queue. # @attribute [r] out_q # @return [Queue] Output queue. class ThreadedEnumerator attr_reader :in_q attr_reader :out_q # Spawns a new thread and does appropriate clean-up # in case thread fails. Propagates exception back # to main thread. # # @yieldparam in_q[Queue] input queue # @yieldparam out_q[Queue] output queue def initialize @in_q = Queue.new @out_q = Queue.new Thread.new do yield @in_q, @out_q @out_q.enq nil rescue StandardError => e @out_q.push e end end def next @in_q.enq :next chunk = @out_q.deq if chunk.is_a? StandardError @out_q.close @in_q.close raise chunk end if chunk.nil? @out_q.close @in_q.close raise StopIteration end chunk end end end end gapic-common-1.2.0/lib/gapic/rest/http_binding_override_configuration.rb0000644000004100000410000000331415143460047026552 0ustar www-datawww-data# Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/config" module Gapic module Rest ## # @private # A specialized Configuration class to use when generating # package-level binding override configuration. # # This configuration is for internal use of the client library classes, # and it is not intended that the end-users will read or change it. # # @attribute [rw] bindings_override # Overrides for http bindings for the RPC of the mixins for the given package. # return [::Hash{::Symbol=>::Array<::Gapic::Rest::GrpcTranscoder::HttpBinding>}] # class HttpBindingOverrideConfiguration extend ::Gapic::Config # @private # Overrides for http bindings for the RPC of the mixins for the given package. # Services in the package should use these when creating clients for the mixin services. # @return [::Hash{::Symbol=>::Array<::Gapic::Rest::GrpcTranscoder::HttpBinding>}] config_attr :bindings_override, {}, ::Hash, nil # @private def initialize parent_config = nil @parent_config = parent_config unless parent_config.nil? yield self if block_given? end end end end gapic-common-1.2.0/lib/gapic/rest/transport_operation.rb0000644000004100000410000000245715143460047023376 0ustar www-datawww-data# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Rest ## # Surfaces information about the active call # from the underlying transport library. # class TransportOperation ## # @private # The underlying transport's library object that describes the active call, if any. # It is not guaranteed to be any specific type, and its value is not guarateed to be stable. # @return [::Object, nil, ::Faraday::Response] attr_reader :underlying_op ## # @private # @param underlying_op [::Object, nil, ::Faraday::Response] # The underlying transport's library object that describes the active call, if any. def initialize underlying_op @underlying_op = underlying_op end end end end gapic-common-1.2.0/lib/gapic/rest/operation.rb0000644000004100000410000000163215143460047021254 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/generic_lro/base_operation" module Gapic module Rest ## # This alias is left here for the backwards compatibility purposes. # Rest LROs now use the same GenericLRO base as the GRPC LROs. # @deprecated Use {Gapic::GenericLRO::BaseOperation} instead. BaseOperation = Gapic::GenericLRO::BaseOperation end end gapic-common-1.2.0/lib/gapic/rest/client_stub.rb0000644000004100000410000003343515143460047021575 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "googleauth" require "gapic/logging_concerns" require "gapic/rest/faraday_middleware" require "gapic/universe_domain_concerns" require "faraday/retry" module Gapic module Rest ## # A class for making REST calls through Faraday # ClientStub's responsibilities: # - wrap Faraday methods with a bounded explicit interface # - store service endpoint and create full url for the request # - store credentials and add auth information to the request # class ClientStub include UniverseDomainConcerns include LoggingConcerns ## # Initializes with an endpoint and credentials # # @param endpoint [String] The endpoint of the API. Overrides any endpoint_template. # @param endpoint_template [String] The endpoint of the API, where the # universe domain component of the hostname is marked by the string in # the constant {UniverseDomainConcerns::ENDPOINT_SUBSTITUTION}. # @param universe_domain [String] The universe domain in which calls # should be made. Defaults to `googleapis.com`. # @param credentials [Google::Auth::Credentials] # Credentials to send with calls in form of a googleauth credentials object. # (see the [googleauth docs](https://googleapis.dev/ruby/googleauth/latest/index.html)) # @param numeric_enums [Boolean] Whether to signal the server to JSON-encode enums as ints # @param raise_faraday_errors [Boolean] # Whether to raise Faraday errors instead of wrapping them in `Gapic::Rest::Error` # Added for backwards compatibility. # Default is `true`. All REST clients (except for old versions of `google-cloud-compute-v1`) # should explicitly set this parameter to `false`. # @param logger [Logger,:default,nil] An explicit logger to use, or one # of the values `:default` (the default) to construct a default logger, # or `nil` to disable logging explicitly. # # @yield [Faraday::Connection] # def initialize credentials:, endpoint: nil, endpoint_template: nil, universe_domain: nil, numeric_enums: false, raise_faraday_errors: true, logging_system: nil, service_name: nil, logger: :default setup_universe_domain universe_domain: universe_domain, endpoint: endpoint, endpoint_template: endpoint_template, credentials: credentials endpoint_url = self.endpoint endpoint_url = "https://#{endpoint_url}" unless /^https?:/.match? endpoint_url endpoint_url = endpoint_url.sub %r{/$}, "" setup_logging logger: logger, system_name: logging_system, service: service_name, endpoint: endpoint_url, client_id: object_id @numeric_enums = numeric_enums @raise_faraday_errors = raise_faraday_errors @connection = Faraday.new url: endpoint_url do |conn| conn.headers = { "Content-Type" => "application/json" } conn.request :google_authorization, self.credentials unless self.credentials.is_a? ::Symbol conn.request :retry conn.response :raise_error conn.adapter :net_http end yield @connection if block_given? end ## # Makes a GET request # # @param uri [String] uri to send this request to # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied # to the REST call. Currently only timeout and headers are supported. # @return [Faraday::Response] def make_get_request uri:, params: {}, options: {}, method_name: nil make_http_request :get, uri: uri, body: nil, params: params, options: options, method_name: method_name end ## # Makes a DELETE request # # @param uri [String] uri to send this request to # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied # to the REST call. Currently only timeout and headers are supported. # @return [Faraday::Response] def make_delete_request uri:, params: {}, options: {}, method_name: nil make_http_request :delete, uri: uri, body: nil, params: params, options: options, method_name: method_name end ## # Makes a PATCH request # # @param uri [String] uri to send this request to # @param body [String] a body to send with the request, nil for requests without a body # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied # to the REST call. Currently only timeout and headers are supported. # @return [Faraday::Response] def make_patch_request uri:, body:, params: {}, options: {}, method_name: nil make_http_request :patch, uri: uri, body: body, params: params, options: options, method_name: method_name end ## # Makes a POST request # # @param uri [String] uri to send this request to # @param body [String] a body to send with the request, nil for requests without a body # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied # to the REST call. Currently only timeout and headers are supported. # @return [Faraday::Response] def make_post_request uri:, body: nil, params: {}, options: {}, method_name: nil make_http_request :post, uri: uri, body: body, params: params, options: options, method_name: method_name end ## # Makes a PUT request # # @param uri [String] uri to send this request to # @param body [String] a body to send with the request, nil for requests without a body # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied # to the REST call. Currently only timeout and headers are supported. # @return [Faraday::Response] def make_put_request uri:, body: nil, params: {}, options: {}, method_name: nil make_http_request :put, uri: uri, body: body, params: params, options: options, method_name: method_name end ## # @private # Sends a http request via Faraday # @param verb [Symbol] http verb # @param uri [String] uri to send this request to # @param body [String, nil] a body to send with the request, nil for requests without a body # @param params [Hash] query string parameters for the request # @param options [::Gapic::CallOptions,Hash] gapic options to be applied to the REST call. # @param is_server_streaming [Boolean] flag if method is streaming # @yieldparam chunk [String] The chunk of data received during server streaming. # @return [Faraday::Response] def make_http_request verb, uri:, body:, params:, options:, is_server_streaming: false, method_name: nil, &block # Converts hash and nil to an options object options = ::Gapic::CallOptions.new(**options.to_h) unless options.is_a? ::Gapic::CallOptions deadline = calculate_deadline options retried_exception = nil next_timeout = get_timeout deadline request_id = LoggingConcerns.random_uuid4 try_number = 1 begin log_request method_name, request_id, try_number, body, options.metadata response = base_make_http_request verb: verb, uri: uri, body: body, params: params, metadata: options.metadata, timeout: next_timeout, is_server_streaming: is_server_streaming, &block log_response method_name, request_id, try_number, response, is_server_streaming response rescue ::Faraday::TimeoutError => e log_response method_name, request_id, try_number, e, is_server_streaming raise if @raise_faraday_errors raise Gapic::Rest::DeadlineExceededError.wrap_faraday_error e, root_cause: retried_exception rescue ::Faraday::Error => e log_response method_name, request_id, try_number, e, is_server_streaming next_timeout = get_timeout deadline if check_retry?(next_timeout) && options.retry_policy.call(e) retried_exception = e try_number += 1 retry end raise if @raise_faraday_errors raise ::Gapic::Rest::Error.wrap_faraday_error e end end ## # @private # Sends a http request via Faraday # # @param verb [Symbol] http verb # @param uri [String] uri to send this request to # @param body [String, nil] a body to send with the request, nil for requests without a body # @param params [Hash] query string parameters for the request # @param metadata [Hash] additional headers for the request # @param is_server_streaming [Boolean] flag if method is streaming # @yieldparam chunk [String] The chunk of data received during server streaming. # @return [Faraday::Response] def base_make_http_request verb:, uri:, body:, params:, metadata:, timeout:, is_server_streaming: false if @numeric_enums && (!params.key?("$alt") || params["$alt"] == "json") params = params.merge({ "$alt" => "json;enum-encoding=int" }) end @connection.send verb, uri do |req| req.params = params if params.any? req.body = body unless body.nil? req.headers = req.headers.merge metadata req.options.timeout = timeout if timeout&.positive? if is_server_streaming req.options.on_data = proc do |chunk, _overall_received_bytes| yield chunk end end end end private ## # Calculates deadline # # @param options [Gapic::CallOptions] call options for this call # # @return [Numeric, nil] Deadline against a POSIX clock_gettime() def calculate_deadline options return if options.timeout.nil? return if options.timeout.negative? Process.clock_gettime(Process::CLOCK_MONOTONIC) + options.timeout end ## # Calculates timeout (seconds) to use as a Faraday timeout # # @param deadline [Numeric, nil] deadline # # @return [Numeric, nil] Timeout (seconds) def get_timeout deadline return if deadline.nil? deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) end ## # Whether the timeout should be retried # # @param timeout [Numeric, nil] # # @return [Boolean] whether the timeout should be retried def check_retry? timeout return true if timeout.nil? timeout.positive? end def log_request method_name, request_id, try_number, body, metadata return unless stub_logger&.enabled? stub_logger.info do |entry| entry.set_system_name entry.set_service entry.set "rpcName", method_name entry.set "retryAttempt", try_number entry.set "requestId", request_id entry.message = "Sending request to #{entry.service}.#{method_name} (try #{try_number})" end body = body.to_s metadata = metadata.to_h rescue {} return if body.empty? && metadata.empty? stub_logger.debug do |entry| entry.set "requestId", request_id entry.set "request", body entry.set "headers", metadata entry.message = "(request payload as JSON)" end end def log_response method_name, request_id, try_number, response, is_server_streaming return unless stub_logger&.enabled? stub_logger.info do |entry| entry.set_system_name entry.set_service entry.set "rpcName", method_name entry.set "retryAttempt", try_number entry.set "requestId", request_id if response.is_a? StandardError entry.set "exception", response.to_s entry.message = "Received error for #{entry.service}.#{method_name} (try #{try_number}): #{response}" elsif is_server_streaming entry.message = "Receiving stream for #{entry.service}.#{method_name} (try #{try_number})" else entry.message = "Received response for #{entry.service}.#{method_name} (try #{try_number})" end end return if is_server_streaming || !response.respond_to?(:body) body = response.body.to_s return if body.empty? stub_logger.debug do |entry| entry.set "requestId", request_id entry.set "response", body entry.message = "(response payload as JSON)" end end end end end gapic-common-1.2.0/lib/gapic/rest/grpc_transcoder/0000755000004100000410000000000015143460047022104 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/rest/grpc_transcoder/http_binding.rb0000644000004100000410000001157515143460047025113 0ustar www-datawww-data# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Rest class GrpcTranscoder ## # @private # A single binding for GRPC-REST transcoding of a request # It includes a uri template with bound field parameters, a HTTP method type, # and a body template # # @attribute [r] method # @return [Symbol] The REST verb for the request. # @attribute [r] template # @return [String] The URI template for the request. # @attribute [r] field_bindings # @return [Array] # The field bindings for the URI template variables. # @attribute [r] body # @return [String] The body template for the request. class HttpBinding attr_reader :method attr_reader :template attr_reader :field_bindings attr_reader :body def initialize method, template, field_bindings, body @method = method @template = template @field_bindings = field_bindings @body = body end ## # @private # Creates a new HttpBinding. # # @param uri_method [Symbol] The rest verb for the binding. # @param uri_template [String] The string with uri template for the binding. # This string will be expanded with the parameters from variable bindings. # @param matches [Array] Variable bindings in an array. Every element # of the array is an [Array] triplet, where: # - the first element is a [String] field path (e.g. `foo.bar`) in the request # to bind to # - the second element is a [Regexp] to match the field value # - the third element is a [Boolean] whether the slashes in the field value # should be preserved (as opposed to escaped) when expanding the uri template. # @param body [String, Nil] The body template, e.g. `*` or a field path. # # @return [Gapic::Rest::GrpcTranscoder::HttpBinding] The new binding. def self.create_with_validation uri_method:, uri_template:, matches: [], body: nil template = uri_template matches.each do |name, _regex, _preserve_slashes| unless uri_template =~ /({#{Regexp.quote name}})/ err_msg = "Binding configuration is incorrect: missing parameter in the URI template.\n" \ "Parameter `#{name}` is specified for matching but there is no corresponding parameter " \ "`{#{name}}` in the URI template." raise ::Gapic::Common::Error, err_msg end template = template.gsub "{#{name}}", "" end if template =~ /{([a-zA-Z_.]+)}/ err_name = Regexp.last_match[1] err_msg = "Binding configuration is incorrect: missing match configuration.\n" \ "Parameter `{#{err_name}}` is specified in the URI template but there is no " \ "corresponding match configuration for `#{err_name}`." raise ::Gapic::Common::Error, err_msg end if body&.include? "." raise ::Gapic::Common::Error, "Provided body template `#{body}` points to a field in a sub-message. This is not supported." end field_bindings = matches.map do |name, regex, preserve_slashes| HttpBinding::FieldBinding.new name, regex, preserve_slashes end HttpBinding.new uri_method, uri_template, field_bindings, body end # A single binding for a field of a request message. # @attribute [r] field_path # @return [String] The path of the bound field, e.g. `foo.bar`. # @attribute [r] regex # @return [Regexp] The regex to match on the bound field's string representation. # @attribute [r] preserve_slashes # @return [Boolean] Whether the slashes in the field value should be preserved # (as opposed to percent-escaped) class FieldBinding attr_reader :field_path attr_reader :regex attr_reader :preserve_slashes def initialize field_path, regex, preserve_slashes @field_path = field_path @regex = regex @preserve_slashes = preserve_slashes end end end end end end gapic-common-1.2.0/lib/gapic/rest/server_stream.rb0000644000004100000410000000656315143460047022145 0ustar www-datawww-data# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "json" module Gapic module Rest ## # A class to provide the Enumerable interface to the response of a REST server-streaming dmethod. # # ServerStream provides the enumerations over the individual response messages within the stream. # # @example normal iteration over resources. # server_stream.each { |response| puts response } # class ServerStream include Enumerable ## # Initializes ServerStream object. # # @param message_klass [Class] # @param json_enumerator [Enumerator] def initialize message_klass, json_enumerator @json_enumerator = json_enumerator @obj = "" @message_klass = message_klass @ready_objs = [] # List of strings end ## # Iterate over JSON objects in the streamed response. # # @yield [Object] Gives one complete Message object. # # @return [Enumerator] if no block is provided # def each return enum_for :each unless block_given? loop do while @ready_objs.empty? begin chunk = @json_enumerator.next next unless chunk next_json! chunk rescue StopIteration dangling_content = @obj.strip error_expl = "Dangling content left after iterating through the stream. " \ "This means that not all content was received or parsed correctly. " \ "It is likely a result of server or network error." error_text = "#{error_expl}\n Content left unparsed: #{dangling_content}" raise Gapic::Common::Error, error_text unless dangling_content.empty? return end end yield @message_klass.decode_json @ready_objs.shift, ignore_unknown_fields: true end end private ## # Builds the next JSON object of the server stream from chunk. # # @param chunk [String] Contains (partial) JSON object # def next_json! chunk chunk.chars.each do |char| # Invariant: @obj is always either a part of a single JSON object or the entire JSON object. # Hence, it's safe to strip whitespace, commans and array brackets. These characters # are only added before @obj is a complete JSON object and essentially can be flushed. next if @obj.empty? && char != "{" @obj += char next unless char == "}" begin # Two choices here: append a Ruby object into # ready_objs or a string. Going with the latter here. JSON.parse @obj @ready_objs.append @obj @obj = "" rescue JSON::ParserError next end end end end end end gapic-common-1.2.0/lib/gapic/rest/paged_enumerable.rb0000644000004100000410000001575715143460047022550 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Rest ## # A class to provide the Enumerable interface to the response of a REST paginated method. # PagedEnumerable assumes response message holds a list of resources and the token to the next page. # # PagedEnumerable provides the enumerations over the resource data, and also provides the enumerations over the # pages themselves. # # @example normal iteration over resources. # paged_enumerable.each { |resource| puts resource } # # @example per-page iteration. # paged_enumerable.each_page { |page| puts page } # # @example Enumerable over pages. # paged_enumerable.each_page do |page| # page.each { |resource| puts resource } # end # # @example more exact operations over pages. # while some_condition() # page = paged_enumerable.page # do_something(page) # break if paged_enumerable.next_page? # paged_enumerable.next_page # end # # @attribute [r] page # @return [Page] The current page object. # class PagedEnumerable include Enumerable attr_reader :page ## # @private # @param service_stub [Object] The REST service_stub with the baseline implementation for the wrapped method. # @param method_name [Symbol] The REST method name that is being wrapped. # @param request [Object] The request object. # @param response [Object] The response object. # @param options [Gapic::CallOptions] The options for making the RPC call. # @param format_resource [Proc] A Proc object to format the resource object. The Proc should accept response as an # argument, and return a formatted resource object. Optional. # def initialize service_stub, method_name, resource_field_name, request, response, options, format_resource: nil @service_stub = service_stub @method_name = method_name @resource_field_name = resource_field_name @request = request @response = response @options = options @format_resource = format_resource @page = Page.new response, resource_field_name, format_resource: @format_resource end ## # Iterate over the individual resources, automatically requesting new pages as needed. # # @yield [Object] Gives the resource objects in the stream. # # @return [Enumerator] if no block is provided # def each &block return enum_for :each unless block_given? each_page do |page| page.each(&block) end end ## # Iterate over the pages. # # @yield [Page] Gives the pages in the stream. # # @return [Enumerator] if no block is provided # def each_page return enum_for :each_page unless block_given? loop do break if @page.nil? yield @page next_page! end end ## # True if there is at least one more page of results. # # @return [Boolean] # def next_page? !next_page_token.nil? && !next_page_token.empty? end ## # Load the next page and set it as the current page. # If there is no next page, sets nil as a current page. # # @return [Page, nil] the new page object. # def next_page! unless next_page? @page = nil return @page end next_request = @request.dup next_request.page_token = @page.next_page_token @response = @service_stub.send @method_name, next_request, @options @page = Page.new @response, @resource_field_name, format_resource: @format_resource end alias next_page next_page! ## # The page token to be used for the next RPC call, or the empty string if there is no next page. # nil if the iteration is complete. # # @return [String, nil] # def next_page_token @page&.next_page_token end ## # The current response object, for the current page. # nil if the iteration is complete. # # @return [Object, nil] # def response @page&.response end ## # A class to represent a page in a PagedEnumerable. This also implements Enumerable, so it can iterate over the # resource elements. # # @attribute [r] response # @return [Object] the response object for the page. class Page include Enumerable attr_reader :response ## # @private # @param response [Object] The response object for the page. # @param resource_field [String] The name of the field in response which holds the resources. # @param format_resource [Proc, nil] A Proc object to format the resource object. Default nil (no formatting). # The Proc should accept response as an argument, and return a formatted resource object. Optional. # def initialize response, resource_field, format_resource: nil @response = response @resource_field = resource_field @format_resource = format_resource end ## # Iterate over the resources. # # @yield [Object] Gives the resource objects in the page. # # @return [Enumerator] if no block is provided # def each return enum_for :each unless block_given? # We trust that the field exists and is an Enumerable resources.each do |resource| resource = @format_resource.call resource if @format_resource yield resource end end ## # The page token to be used for the next RPC call, or the empty string if there is no next page. # # @return [String] # def next_page_token @response.next_page_token end ## # Whether the next_page_token exists and is not empty # # @return [Boolean] # def next_page_token? !next_page_token.empty? end ## # Resources in this page presented as an array. # When the iterable is a protobuf map, the `.each |item|` gives just the keys # to iterate like a normal hash it should be converted to an array first # # @return [Array] # def resources @resources ||= @response[@resource_field].to_a end end end end end gapic-common-1.2.0/lib/gapic/rest/grpc_transcoder.rb0000644000004100000410000002776015143460047022445 0ustar www-datawww-data# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/rest/grpc_transcoder/http_binding" module Gapic module Rest # @private # Transcodes a proto request message into HTTP Rest call components # using a configuration of bindings. # Internal doc go/actools-regapic-grpc-transcoding. class GrpcTranscoder def initialize bindings = nil @bindings = bindings || [] end ## # @private # Creates a new trascoder that is a copy of this one, but with an additional # binding defined by the parameters. # # @param uri_method [Symbol] The rest verb for the binding. # @param uri_template [String] The string with uri template for the binding. # This string will be expanded with the parameters from variable bindings. # @param matches [Array] Variable bindings in an array. Every element # of the array is an [Array] triplet, where: # - the first element is a [String] field path (e.g. `foo.bar`) in the request # to bind to # - the second element is a [Regexp] to match the field value # - the third element is a [Boolean] whether the slashes in the field value # should be preserved (as opposed to escaped) when expanding the uri template. # @param body [String, Nil] The body template, e.g. `*` or a field path. # # @return [Gapic::Rest::GrpcTranscoder] The updated transcoder. def with_bindings uri_method:, uri_template:, matches: [], body: nil binding = HttpBinding.create_with_validation(uri_method: uri_method, uri_template: uri_template, matches: matches, body: body) GrpcTranscoder.new @bindings + [binding] end ## # @private # Performs the full grpc transcoding -- creating a REST request from the GRPC request # by matching the http bindings and choosing the last one to match. # From the matching binding and the request the following components of the REST request # are produced: # - A [Symbol] representing the Rest verb (e.g. `:get`) # - Uri [String] (e.g. `books/100:read`) # - Query string params in the form of key-value pairs [Array] # (e.g. [["foo", "bar"], ["baz", "qux"]]) # - Body of the request [String] # # @param request [Object] The GRPC request object # # @return [Array] The components of the transcoded request. def transcode request # Using bindings in reverse here because of the "last one wins" rule @bindings.reverse.each do |http_binding| # The main reason we are using request.to_json here # is that the unset proto3_optional fields will not be # in that JSON, letting us skip the checks that would look like # `request.respond_to?("has_#{key}?".to_sym) && !request.send("has_#{key}?".to_sym)` # The reason we set emit_defaults: true is to avoid # having to figure out default values for the required # fields at a runtime. # # Make a new one for each binding because extract_scalar_value! is destructive request_hash = JSON.parse request.to_json emit_defaults: true uri_values = bind_uri_values! http_binding, request_hash next if uri_values.any? { |_, value| value.nil? } # Note that the body template can only point to a top-level field, # so there is no need to split the path. next if http_binding.body && http_binding.body != "*" && !(request.respond_to? http_binding.body.to_sym) method = http_binding.method uri = expand_template http_binding.template, uri_values body, query_params = construct_body_query_params http_binding.body, request_hash, request return method, uri, query_params, body end raise ::Gapic::Common::Error, "Request object does not match any transcoding template. Cannot form a correct REST call." end private # Binds request values for the uri template expansion. # This method modifies the provided `request_hash` parameter. # Returned values are percent-escaped with slashes potentially preserved. # @param http_binding [Gapic::Rest::GrpcTranscoder::HttpBinding] # Http binding to get the field bindings from. # @param request_hash [Hash] # A hash of the GRPC request with the unset proto3_optional fields pre-removed. # !!! This hash will be modified. The bound fields will be deleted. !!! # @return [Hash{String, String}] # Name to value hash of the variables for the uri template expansion. # The values are percent-escaped with slashes potentially preserved. def bind_uri_values! http_binding, request_hash http_binding.field_bindings.to_h do |field_binding| field_path_camel = field_binding.field_path.split(".").map { |part| camel_name_for part }.join(".") field_value = extract_scalar_value! request_hash, field_path_camel, field_binding.regex if field_value field_value = field_value.split("/").map { |segment| percent_escape segment }.join("/") end [field_binding.field_path, field_value] end end # Percent-escapes a string. # @param str [String] String to escape. # @return [String] Escaped string. def percent_escape str # `+` to represent spaces is not currently supported in Showcase server. CGI.escape(str).gsub("+", "%20") end # Constructs body and query parameters for the Rest request. # @param body_template [String, Nil] The template for the body, e.g. `*`. # @param request_hash_without_uri [Hash] # The hash of the GRPC request with the unset proto3_optional fields # and the values that are bound to URI removed. # @param request [Object] The GRPC request. # @return [Array{String, Array}] A pair of body and query parameters. def construct_body_query_params body_template, request_hash_without_uri, request body = "" query_params = [] if body_template == "*" body = request_hash_without_uri.to_json elsif body_template && body_template != "" # Using a `request` here instead of `request_hash_without_uri` # because if `body` is bound to a message field, # the fields of the corresponding sub-message, # which were used when constructing the URI, should not be deleted # (as opposed to the case when `body` is `*`). # # The `request_hash_without_uri` at this point was mutated to delete these fields. # # Note 1: body template can only point to a top-level field. # Note 2: The field that body template points to can be null, in which case # an empty string should be sent. E.g. `Compute.Projects.SetUsageExportBucket`. request_body_field = request.send body_template.to_sym if request.respond_to? body_template.to_sym if request_body_field request_hash_without_uri.delete camel_name_for body_template body = request_body_field.to_json emit_defaults: true end query_params = build_query_params request_hash_without_uri else query_params = build_query_params request_hash_without_uri end [body, query_params] end # Builds query params for the REST request. # This function calls itself recursively for every submessage field, passing # the submessage hash as request and the path to the submessage field as a prefix. # @param request_hash [Hash] # A hash of the GRPC request or the sub-request with the unset # proto3_optional fields and the values that are bound to URI removed. # @param prefix [String] A prefix to form the correct query parameter key. # @return [Array{String, String}] Query string params as key-value pairs. def build_query_params request_hash, prefix = "" result = [] request_hash.each do |key, value| full_key_name = "#{prefix}#{key}" case value when ::Array value.each do |_val| result.push "#{full_key_name}=#{value}" end when ::Hash result += build_query_params value, "#{full_key_name}." else result.push "#{full_key_name}=#{value}" unless value.nil? end end result end # Extracts a non-submessage non-array value from the request hash by path # if its string representation matches the regex provided. # This method modifies the provided `request_hash` parameter. # Returns nil if: # - the field is not found # - the field is a Message or an array, # - the regex does not match # @param request_hash [Hash] # A hash of the GRPC request or the sub-request with the unset # proto3_optional fields removed. # !!! This hash will be modified. The extracted field will be deleted. !!! # @param field_path [String] A path to the field, e.g. `foo.bar`. # @param regex [Regexp] A regex to match on the field's string representation. # @return [String, Nil] the field's string representation or nil. def extract_scalar_value! request_hash, field_path, regex parent, name = find_value request_hash, field_path value = parent.delete name # Covers the case where in `foo.bar.baz`, `baz` is still a submessage or an array. return nil if value.is_a?(::Hash) || value.is_a?(::Array) value.to_s if value.to_s =~ regex end # Finds a value in the hash by path. # @param request_hash [Hash] A hash of the GRPC request or the sub-request. # @param field_path [String] A path of the field, e.g. `foo.bar`. def find_value request_hash, field_path path_split = field_path.split "." value_parent = nil value = request_hash last_field_name = nil path_split.each do |curr_field| # Covers the case when in `foo.bar.baz`, `bar` is not a submessage field # or is a submessage field initialized with nil. return {}, nil unless value.is_a? ::Hash value_parent = value last_field_name = curr_field value = value[curr_field] end [value_parent, last_field_name] end # Performs variable expansion on the template using the bindings provided # @param template [String] The Uri template. # @param bindings [Hash{String, String}] # The variable bindings. The values should be percent-escaped # (with slashes potentially preserved). # @return [String] The expanded template. def expand_template template, bindings result = template bindings.each do |name, value| result = result.gsub "{#{name}}", value end result end ## # Converts a snake_case parameter name into camelCase for query string parameters. # @param attr_name [String] Parameter name. # @return [String] Camel-cased parameter name. def camel_name_for attr_name parts = attr_name.split "_" first_part = parts[0] other_parts = parts[1..] other_parts_pascal = other_parts.map(&:capitalize).join "#{first_part}#{other_parts_pascal}" end end end end gapic-common-1.2.0/lib/gapic/protobuf.rb0000644000004100000410000001126615143460047020143 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "google/protobuf/timestamp_pb" module Gapic ## # A set of internal utilities for coercing data to protobuf messages. # module Protobuf ## # Creates an instance of a protobuf message from a hash that may include nested hashes. `google/protobuf` allows # for the instantiation of protobuf messages using hashes but does not allow for nested hashes to instantiate # nested submessages. # # @param hash [Hash, Object] The hash to be converted into a proto message. If an instance of the proto message # class is given, it is returned unchanged. # @param to [Class] The corresponding protobuf message class of the given hash. # # @return [Object] An instance of the given message class. def self.coerce hash, to: return hash if hash.is_a? to return nil if hash.nil? # Special case handling of certain types return time_to_timestamp hash if to == Google::Protobuf::Timestamp && hash.is_a?(Time) # Sanity check: input must be a Hash raise ArgumentError, "Value #{hash} must be a Hash or a #{to.name}" unless hash.is_a? Hash hash = coerce_submessages hash, to.descriptor to.new hash end ## # Coerces values of the given hash to be acceptable by the instantiation method provided by `google/protobuf` # # @private # # @param hash [Hash] The hash whose nested hashes will be coerced. # @param message_descriptor [Google::Protobuf::Descriptor] The protobuf descriptor for the message. # # @return [Hash] A hash whose nested hashes have been coerced. def self.coerce_submessages hash, message_descriptor return nil if hash.nil? coerced = {} hash.each do |key, val| field_descriptor = message_descriptor.lookup key.to_s coerced[key] = if field_descriptor&.type == :message coerce_submessage val, field_descriptor elsif field_descriptor&.type == :bytes && (val.is_a?(IO) || val.is_a?(StringIO)) val.binmode.read else # For non-message fields, just pass the scalar value through. # Note: if field_descriptor is not found, we just pass the value # through and let protobuf raise an error. val end end coerced end ## # Coerces a message-typed field. # The field can be a normal single message, a repeated message, or a map. # # @private # # @param val [Object] The value to coerce # @param field_descriptor [Google::Protobuf::FieldDescriptor] The field descriptor. # def self.coerce_submessage val, field_descriptor if val.is_a? Array # Assume this is a repeated message field, iterate over it and coerce # each to the message class. # Protobuf will raise an error if this assumption is incorrect. val.map do |elem| coerce elem, to: field_descriptor.subtype.msgclass end elsif field_descriptor.label == :repeated # Non-array passed to a repeated field: assume this is a map, and that # a hash is being passed, and let protobuf handle the conversion. # Protobuf will raise an error if this assumption is incorrect. val else # Assume this is a normal single message, and coerce to the message # class. coerce val, to: field_descriptor.subtype.msgclass end end ## # Utility for converting a Google::Protobuf::Timestamp instance to a Ruby time. # # @param timestamp [Google::Protobuf::Timestamp] The timestamp to be converted. # # @return [Time] The converted Time. def self.timestamp_to_time timestamp Time.at timestamp.seconds, timestamp.nanos, :nanosecond end ## # Utility for converting a Ruby Time instance to a Google::Protobuf::Timestamp. # # @param time [Time] The Time to be converted. # # @return [Google::Protobuf::Timestamp] The converted Google::Protobuf::Timestamp. def self.time_to_timestamp time Google::Protobuf::Timestamp.new seconds: time.to_i, nanos: time.nsec end private_class_method :coerce_submessages, :coerce_submessage end end gapic-common-1.2.0/lib/gapic/grpc/0000755000004100000410000000000015143460047016703 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/grpc/service_stub.rb0000644000004100000410000002402215143460047021725 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc" require "googleauth" require "gapic/grpc/service_stub/rpc_call" require "gapic/grpc/service_stub/channel" require "gapic/grpc/service_stub/channel_pool" require "gapic/logging_concerns" require "gapic/universe_domain_concerns" module Gapic ## # Gapic gRPC Stub # # This class wraps the actual gRPC Stub and ChannelPool objects. # # @!attribute [r] grpc_stub # @return [Object] The instance of the gRPC stub class (`grpc_stub_class`) constructor argument. # @!attribute [r] channel_pool # @return [Gapic::ServiceStub::ChannelPool] The instance of the ChannelPool class. # class ServiceStub include UniverseDomainConcerns include LoggingConcerns attr_reader :grpc_stub attr_reader :channel_pool ## # Creates a Gapic gRPC stub object. # # @param grpc_stub_class [Class] gRPC stub class to create a new instance of. # @param endpoint [String] The endpoint of the API. Overrides any endpoint_template. # @param endpoint_template [String] The endpoint of the API, where the # universe domain component of the hostname is marked by the string in # the constant {UniverseDomainConcerns::ENDPOINT_SUBSTITUTION}. # @param universe_domain [String] The universe domain in which calls should # be made. Defaults to `googleapis.com`. # @param credentials [Google::Auth::Credentials, Signet::OAuth2::Client, String, Hash, Proc, # ::GRPC::Core::Channel, ::GRPC::Core::ChannelCredentials] Provides the means for authenticating requests made by # the client. This parameter can be many types: # # * A `Google::Auth::Credentials` uses a the properties of its represented keyfile for authenticating requests # made by this client. # * A `Signet::OAuth2::Client` object used to apply the OAuth credentials. # * A `::GRPC::Core::Channel` will be used to make calls through. # * A `::GRPC::Core::ChannelCredentials` for the setting up the RPC client. The channel credentials should # already be composed with a `::GRPC::Core::CallCredentials` object. # * A `Proc` will be used as an updater_proc for the Grpc channel. The proc transforms the metadata for # requests, generally, to give OAuth credentials. # @param channel_args [Hash] The channel arguments. (This argument is ignored when `credentials` is # provided as a `::GRPC::Core::Channel`.) # @param interceptors [Array<::GRPC::ClientInterceptor>] An array of {::GRPC::ClientInterceptor} objects that will # be used for intercepting calls before they are executed Interceptors are an EXPERIMENTAL API. # @param channel_pool_config [::Gapic::ServiceStub:ChannelPool::Configuration] The configuration for channel # pool. This argument will raise error when `credentials` is provided as a `::GRPC::Core::Channel`. # @param logger [Logger,:default,nil] An explicit logger to use, or one # of the values `:default` (the default) to construct a default logger, # or `nil` to disable logging explicitly. # def initialize grpc_stub_class, credentials:, endpoint: nil, endpoint_template: nil, universe_domain: nil, channel_args: nil, interceptors: nil, channel_pool_config: nil, logger: :default raise ArgumentError, "grpc_stub_class is required" if grpc_stub_class.nil? setup_universe_domain universe_domain: universe_domain, endpoint: endpoint, endpoint_template: endpoint_template, credentials: credentials setup_logging logger: logger, system_name: grpc_stub_class, service: grpc_stub_class, endpoint: self.endpoint, client_id: object_id @channel_pool = nil @grpc_stub = nil channel_args = Hash channel_args interceptors = Array interceptors if channel_pool_config && channel_pool_config.channel_count > 1 create_channel_pool grpc_stub_class, endpoint: self.endpoint, credentials: self.credentials, channel_args: channel_args, interceptors: interceptors, channel_pool_config: channel_pool_config else create_grpc_stub grpc_stub_class, endpoint: self.endpoint, credentials: self.credentials, channel_args: channel_args, interceptors: interceptors end end def create_channel_pool grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil, channel_pool_config: nil if credentials.is_a? ::GRPC::Core::Channel raise ArgumentError, "Cannot create a channel pool with GRPC::Core::Channel as credentials" end @channel_pool = ChannelPool.new grpc_stub_class, endpoint: endpoint, credentials: credentials, channel_args: channel_args, interceptors: interceptors, config: channel_pool_config, stub_logger: stub_logger end def create_grpc_stub grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil @grpc_stub = case credentials when ::GRPC::Core::Channel grpc_stub_class.new endpoint, nil, channel_override: credentials, interceptors: interceptors when ::GRPC::Core::ChannelCredentials, Symbol grpc_stub_class.new endpoint, credentials, channel_args: channel_args, interceptors: interceptors else updater_proc = credentials.updater_proc if credentials.respond_to? :updater_proc updater_proc ||= credentials if credentials.is_a? Proc raise ArgumentError, "invalid credentials (#{credentials.class})" if updater_proc.nil? call_creds = ::GRPC::Core::CallCredentials.new updater_proc chan_creds = ::GRPC::Core::ChannelCredentials.new.compose call_creds grpc_stub_class.new endpoint, chan_creds, channel_args: channel_args, interceptors: interceptors end end ## # Invoke the specified RPC call. # # @param method_name [Symbol] The RPC method name. # @param request [Object] The request object. # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to # customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. This object # should only be used once. # # @yield [response, operation] Access the response along with the RPC operation. # @yieldparam response [Object] The response object. # @yieldparam operation [::GRPC::ActiveCall::Operation] The RPC operation for the response. # # @return [Object] The response object. # # @example # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # # request = Google::Showcase::V1beta1::EchoRequest.new # response = echo_stub.call_rpc :echo, request # # @example Using custom call options: # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # # request = Google::Showcase::V1beta1::EchoRequest.new # options = Gapic::CallOptions.new( # retry_policy = { # retry_codes: [::GRPC::Core::StatusCodes::UNAVAILABLE] # } # ) # response = echo_stub.call_rpc :echo, request # options: options # # @example Accessing the response and RPC operation using a block: # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # # request = Google::Showcase::V1beta1::EchoRequest.new # echo_stub.call_rpc :echo, request do |response, operation| # operation.trailing_metadata # end # def call_rpc method_name, request, options: nil, &block if @channel_pool.nil? meth = @grpc_stub.method method_name rpc_call = RpcCall.new meth, stub_logger: stub_logger, method_name: method_name rpc_call.call request, options: options, &block else @channel_pool.call_rpc method_name, request, options: options, &block end end end end gapic-common-1.2.0/lib/gapic/grpc/service_stub/0000755000004100000410000000000015143460047021400 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/grpc/service_stub/channel.rb0000644000004100000410000001005215143460047023333 0ustar www-datawww-data# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc" require "googleauth" require "gapic/grpc/service_stub/rpc_call" module Gapic class ServiceStub ## # @private # # Gapic gRPC ServiceStub Channel. # # This class wraps the gRPC stub object and its RPC methods. # class Channel attr_reader :concurrent_streams ## # Creates a new Channel instance # def initialize grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil, on_channel_create: nil, stub_logger: nil @grpc_stub_class = grpc_stub_class @endpoint = endpoint @credentials = credentials @channel_args = Hash channel_args @interceptors = Array interceptors @stub_logger = stub_logger @concurrent_streams = 0 @mutex = Mutex.new setup_grpc_stub on_channel_create&.call self end ## # Creates a gRPC stub object # def setup_grpc_stub raise ArgumentError, "grpc_stub_class is required" if @grpc_stub_class.nil? raise ArgumentError, "endpoint is required" if @endpoint.nil? raise ArgumentError, "credentials is required" if @credentials.nil? @grpc_stub = case @credentials when ::GRPC::Core::Channel @grpc_stub_class.new @endpoint, nil, channel_override: @credentials, interceptors: @interceptors when ::GRPC::Core::ChannelCredentials, Symbol @grpc_stub_class.new @endpoint, @credentials, channel_args: @channel_args, interceptors: @interceptors else updater_proc = @credentials.updater_proc if @credentials.respond_to? :updater_proc updater_proc ||= @credentials if @credentials.is_a? Proc raise ArgumentError, "invalid credentials (#{credentials.class})" if updater_proc.nil? call_creds = ::GRPC::Core::CallCredentials.new updater_proc chan_creds = ::GRPC::Core::ChannelCredentials.new.compose call_creds @grpc_stub_class.new @endpoint, chan_creds, channel_args: @channel_args, interceptors: @interceptors end end ## # Invoke the specified RPC call. # # @param method_name [Symbol] The RPC method name. # @param request [Object] The request object. # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to # customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. This object # should only be used once. # # @yield [response, operation] Access the response along with the RPC operation. # @yieldparam response [Object] The response object. # @yieldparam operation [::GRPC::ActiveCall::Operation] The RPC operation for the response. # # @return [Object] The response object. # def call_rpc method_name, request, options: nil, &block @mutex.synchronize { @concurrent_streams += 1 } begin meth = @grpc_stub.method method_name rpc_call = RpcCall.new meth, stub_logger: @stub_logger, method_name: method_name response = rpc_call.call request, options: options, &block response ensure @mutex.synchronize { @concurrent_streams -= 1 } end end end end end gapic-common-1.2.0/lib/gapic/grpc/service_stub/channel_pool.rb0000644000004100000410000000775715143460047024406 0ustar www-datawww-data# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc" require "googleauth" require "gapic/config" module Gapic class ServiceStub ## # @private # # Gapic gRPC ServiceStub ChannelPool # # This class wraps multiple channels for sending RPCs. # class ChannelPool ## # Initialize an instance of ServiceStub::ChannelPool # def initialize grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil, config: nil, stub_logger: nil if credentials.is_a? ::GRPC::Core::Channel raise ArgumentError, "Can't create a channel pool with GRPC::Core::Channel as credentials" end @grpc_stub_class = grpc_stub_class @endpoint = endpoint @credentials = credentials @channel_args = channel_args @interceptors = interceptors @config = config || Configuration.new @stub_logger = stub_logger @channels = (1..@config.channel_count).map { create_channel } end ## # Creates a new channel. def create_channel Channel.new @grpc_stub_class, endpoint: @endpoint, credentials: @credentials, channel_args: @channel_args, interceptors: @interceptors, on_channel_create: @config.on_channel_create, stub_logger: @stub_logger end ## # Invoke the specified RPC call. # # @param method_name [Symbol] The RPC method name. # @param request [Object] The request object. # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to # customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. This object # should only be used once. # # @yield [response, operation] Access the response along with the RPC operation. # @yieldparam response [Object] The response object. # @yieldparam operation [::GRPC::ActiveCall::Operation] The RPC operation for the response. # # @return [Object] The response object. # def call_rpc method_name, request, options: nil, &block unless @config.channel_selection == :least_loaded warn "Invalid channel selection configuration, resorting to least loaded channel" end channel = least_loaded_channel channel.call_rpc method_name, request, options: options, &block end private ## # Return the least loaded channel in the pool # # @return [::Grpc::ServiceStub::Channel] # def least_loaded_channel @channels.min_by(&:concurrent_streams) end ## # Configuration class for ChannelPool # # @!attribute [rw] channel_count # The number of channels in the channel pool. # return [Integer] # @!attribute [rw] on_channel_create # Proc to run at the end of each channel initialization. # Proc is provided ::Gapic::ServiceStub::Channel object as input. # return [Proc] # @!attribute [rw] channel_selection # The algorithm for selecting a channel for an RPC. # return [Symbol] # class Configuration extend ::Gapic::Config config_attr :channel_count, 1, ::Integer config_attr :on_channel_create, nil, ::Proc config_attr :channel_selection, :least_loaded, :least_loaded end end end end gapic-common-1.2.0/lib/gapic/grpc/service_stub/rpc_call.rb0000644000004100000410000002331315143460047023506 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/call_options" require "gapic/logging_concerns" require "grpc/errors" module Gapic class ServiceStub class RpcCall attr_reader :stub_method ## # Creates an API object for making a single RPC call. # # In typical usage, `stub_method` will be a proc used to make an RPC request. This will mostly likely be a bound # method from a request Stub used to make an RPC call. # # The result is created by applying a series of function decorators defined in this module to `stub_method`. # # The result is another proc which has the same signature as the original. # # @param stub_method [Proc] Used to make a bare rpc call. # def initialize stub_method, stub_logger: nil, method_name: nil @stub_method = stub_method @stub_logger = stub_logger @method_name = method_name @request_id = LoggingConcerns.random_uuid4 end ## # Invoke the RPC call. # # @param request [Object] The request object. # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to # customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. This object # should only be used once. # # @yield [response, operation] Access the response along with the RPC operation. Additionally, throwing # `:response, obj` within the block will change the return value to `obj`. # @yieldparam response [Object] The response object. # @yieldparam operation [::GRPC::ActiveCall::Operation] The RPC operation for the response. # # @return [Object] The response object. # # @example # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # echo_call = Gapic::ServiceStub::RpcCall.new echo_stub.method :echo # # request = Google::Showcase::V1beta1::EchoRequest.new # response = echo_call.call request # # @example Using custom call options: # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # echo_call = Gapic::ServiceStub::RpcCall.new echo_stub.method :echo # # request = Google::Showcase::V1beta1::EchoRequest.new # options = Gapic::CallOptions.new( # retry_policy = { # retry_codes: [::GRPC::Core::StatusCodes::UNAVAILABLE] # } # ) # response = echo_call.call request, options: options # # @example Accessing the RPC operation using a block: # require "google/showcase/v1beta1/echo_pb" # require "google/showcase/v1beta1/echo_services_pb" # require "gapic" # require "gapic/grpc" # # echo_channel = ::GRPC::Core::Channel.new( # "localhost:7469", nil, :this_channel_is_insecure # ) # echo_stub = Gapic::ServiceStub.new( # Google::Showcase::V1beta1::Echo::Stub, # endpoint: "localhost:7469", credentials: echo_channel # ) # echo_call = Gapic::ServiceStub::RpcCall.new echo_stub.method :echo # # request = Google::Showcase::V1beta1::EchoRequest.new # metadata = echo_call.call request do |_response, operation| # throw :response, operation.trailing_metadata # end # def call request, options: nil # Converts hash and nil to an options object options = Gapic::CallOptions.new(**options.to_h) if options.respond_to? :to_h deadline = calculate_deadline options metadata = options.metadata try_number = 1 retried_exception = nil begin request = log_request request, metadata, try_number operation = stub_method.call request, deadline: deadline, metadata: metadata, return_op: true response = operation.execute catch :response do response = log_response response, try_number yield response, operation if block_given? response end rescue ::GRPC::DeadlineExceeded => e log_response e, try_number raise Gapic::GRPC::DeadlineExceededError.new e.message, root_cause: retried_exception rescue StandardError => e e = normalize_exception e log_response e, try_number if check_retry?(deadline) && options.retry_policy.call(e) retried_exception = e try_number += 1 retry end raise e end end private def calculate_deadline options return if options.timeout.nil? return if options.timeout.negative? current_time + options.timeout end def check_retry? deadline return true if deadline.nil? deadline > current_time end def current_time # An alternative way of saying Time.now without actually calling # Time.now. This allows clients that replace Time.now (e.g. via the # timecop gem) to do so without interfering with the deadline. nanos = Process.clock_gettime Process::CLOCK_REALTIME, :nanosecond secs_part = nanos / 1_000_000_000 nsecs_part = nanos % 1_000_000_000 Time.at secs_part, nsecs_part, :nanosecond end def normalize_exception exception if exception.is_a?(::GRPC::Unavailable) && /Signet::AuthorizationError/ =~ exception.message exception = Gapic::GRPC::AuthorizationError.new exception.message.gsub(%r{^\d+:}, "") end exception end def log_request request, metadata, try_number return request unless @stub_logger&.enabled? @stub_logger.info do |entry| entry.set_system_name entry.set_service entry.set "rpcName", @method_name entry.set "retryAttempt", try_number entry.set "requestId", @request_id entry.message = if request.is_a? Enumerable "Sending stream to #{entry.service}.#{@method_name} (try #{try_number})" else "Sending request to #{entry.service}.#{@method_name} (try #{try_number})" end end loggable_metadata = metadata.to_h rescue {} if request.is_a? Enumerable request.lazy.map do |req| log_single_request req, loggable_metadata end else log_single_request request, loggable_metadata end end def log_single_request request, metadata request_content = request.respond_to?(:to_h) ? (request.to_h rescue {}) : request.to_s if !request_content.empty? || !metadata.empty? @stub_logger.debug do |entry| entry.set "requestId", @request_id entry.set "request", request_content entry.set "headers", metadata entry.message = "(request payload as #{request.class})" end end request end def log_response response, try_number return response unless @stub_logger&.enabled? @stub_logger.info do |entry| entry.set_system_name entry.set_service entry.set "rpcName", @method_name entry.set "retryAttempt", try_number entry.set "requestId", @request_id case response when StandardError entry.set "exception", response.to_s entry.message = "Received error for #{entry.service}.#{@method_name} (try #{try_number}): #{response}" when Enumerable entry.message = "Receiving stream for #{entry.service}.#{@method_name} (try #{try_number})" else entry.message = "Received response for #{entry.service}.#{@method_name} (try #{try_number})" end end case response when StandardError response when Enumerable response.lazy.map do |resp| log_single_response resp end else log_single_response response end end def log_single_response response response_content = response.respond_to?(:to_h) ? (response.to_h rescue {}) : response.to_s unless response_content.empty? @stub_logger.debug do |entry| entry.set "requestId", @request_id entry.set "response", response_content entry.message = "(response payload as #{response.class})" end end response end end end end gapic-common-1.2.0/lib/gapic/grpc/status_details.rb0000644000004100000410000000234015143460047022257 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc" require "grpc/errors" require "grpc/google_rpc_status_utils" require "google/protobuf/well_known_types" # Required in order to deserialize common error detail proto types require "google/rpc/error_details_pb" module GRPC class BadStatus < StandardError def status_details rpc_status = to_rpc_status return nil.to_a if rpc_status.nil? rpc_status.details.map do |detail| detail_type = Google::Protobuf::DescriptorPool.generated_pool.lookup detail.type_name detail = detail.unpack detail_type.msgclass if detail_type detail rescue Google::Protobuf::ParseError detail end end end end gapic-common-1.2.0/lib/gapic/grpc/errors.rb0000644000004100000410000000405215143460047020545 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "googleauth" require "gapic/common/error" module Gapic module GRPC ## # An error class to represent the Authorization Error. # The GRPC layer wraps auth plugin errors in ::GRPC::Unavailable. # This class rewraps those GRPC layer errors, presenting a correct status code. # class AuthorizationError < ::GRPC::Unauthenticated end ## # An error class that represents Deadline Exceeded error with an optional # retry root cause. # # The GRPC layer throws ::GRPC::DeadlineExceeded without any context. # If the deadline was exceeded while retrying another exception (e.g. # ::GRPC::Unavailable), that exception could be useful for understanding # the readon for the timeout. # # This exception rewraps ::GRPC::DeadlineExceeded, adding an exception # that was being retried until the deadline was exceeded (if any) as a # `root_cause` attribute. # # @!attribute [r] root_cause # @return [Object, nil] The exception that was being retried # when the DeadlineExceeded error occured. # class DeadlineExceededError < ::GRPC::DeadlineExceeded attr_reader :root_cause ## # @param message [String] The error message. # # @param root_cause [Object, nil] The exception that was being retried # when the DeadlineExceeded error occured. # def initialize message, root_cause: nil super message @root_cause = root_cause end end end end gapic-common-1.2.0/lib/gapic/stream_input.rb0000644000004100000410000000357015143460047021014 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic ## # Manages requests for an input stream and holds the stream open until {#close} is called. # class StreamInput ## # Create a new input stream object to manage streaming requests and hold the stream open until {#close} is called. # # @param requests [Object] # def initialize *requests @queue = Queue.new # Push initial requests into the queue requests.each { |request| @queue.push request } end ## # Adds a request object to the stream. # # @param request [Object] # # @return [StreamInput] Returns self. # def push request @queue.push request self end alias << push alias append push ## # Closes the stream. # # @return [StreamInput] Returns self. # def close @queue.push self self end ## # @private # Iterates the requests given to the stream. # # @yield [request] The block for accessing each request. # @yieldparam [Object] request The request object. # # @return [Enumerator] An Enumerator is returned if no block is given. # def to_enum return enum_for :to_enum unless block_given? loop do request = @queue.pop break if request.equal? self yield request end end end end gapic-common-1.2.0/lib/gapic/config.rb0000644000004100000410000000701615143460047017546 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic ## # Config is a simple DSL for creating Configuration classes. # # @example # require "gapic/config" # # class SampleConfig # extend Gapic::Config # # config_attr :name, nil, String, nil # config_attr :active, true, true, false # config_attr :count, nil, Numeric, nil # config_attr :env, :production, String, Symbol # # def initialize parent_config = nil # @parent_config = parent_config unless parent_config.nil? # yield self if block_given? # end # end # # config = SampleConfig.new # # config.name #=> nil # config.name = "thor" #=> "thor" # config.name #=> "thor" # config.name = :thor # ArgumentError # module Config ## # Add configuration attribute methods to the configuratin class. # # @param [String, Symbol] name The name of the option # @param [Object, nil] default Initial value (nil is allowed) # @param [Array] valid_values A list of valid types # def config_attr name, default, *valid_values, &validator name = String(name).to_sym name_setter = :"#{name}=" raise NameError, "invalid config name #{name}" if name !~ /^[a-zA-Z]\w*$/ || name == :parent_config raise NameError, "method #{name} already exists" if method_defined? name raise NameError, "method #{name_setter} already exists" if method_defined? name_setter raise ArgumentError, "validation must be provided" if validator.nil? && valid_values.empty? validator ||= ->(value) { valid_values.any? { |v| v === value } } name_ivar = :"@#{name}" create_getter name_ivar, name, default create_setter name_ivar, name_setter, default, validator end private def create_getter name_ivar, name, default define_method name do return instance_variable_get name_ivar if instance_variable_defined? name_ivar if instance_variable_defined? :@parent_config parent = instance_variable_get :@parent_config return parent.__send__ name if parent.respond_to? name end default end end def create_setter name_ivar, name_setter, default, validator define_method name_setter do |new_value| valid_value = validator.call new_value if new_value.nil? # Always allow nil when a default value is present valid_value ||= !default.nil? valid_value ||= begin # Allow nil if parent config has the getter method. parent = instance_variable_get :@parent_config if instance_variable_defined? :@parent_config parent&.respond_to? name_setter end end raise ArgumentError unless valid_value if new_value.nil? remove_instance_variable name_ivar if instance_variable_defined? name_ivar else instance_variable_set name_ivar, new_value end end end end end gapic-common-1.2.0/lib/gapic/common/0000755000004100000410000000000015143460047017240 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/common/retry_policy.rb0000644000004100000410000001752715143460047022325 0ustar www-datawww-data# Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common/error_codes" module Gapic module Common ## # Gapic Common retry policy base class. # class RetryPolicy # @return [Numeric] Default initial delay in seconds. DEFAULT_INITIAL_DELAY = 1 # @return [Numeric] Default maximum delay in seconds. DEFAULT_MAX_DELAY = 15 # @return [Numeric] Default delay scaling factor for subsequent retry attempts. DEFAULT_MULTIPLIER = 1.3 # @return [Array] Default list of retry codes. DEFAULT_RETRY_CODES = [].freeze # @return [Numeric] Default timeout threshold value in seconds. DEFAULT_TIMEOUT = 3600 # One hour ## # Create new Gapic::Common::RetryPolicy instance. # # @param initial_delay [Numeric] Initial delay in seconds. # @param max_delay [Numeric] Maximum delay in seconds. # @param multiplier [Numeric] The delay scaling factor for each subsequent retry attempt. # @param retry_codes [Array] List of retry codes. # @param timeout [Numeric] Timeout threshold value in seconds. # def initialize initial_delay: nil, max_delay: nil, multiplier: nil, retry_codes: nil, timeout: nil # Instance values are set as `nil` to determine whether values are overriden from default. @initial_delay = initial_delay @max_delay = max_delay @multiplier = multiplier @retry_codes = convert_codes retry_codes @timeout = timeout start! end # @return [Numeric] Initial delay in seconds. def initial_delay @initial_delay || DEFAULT_INITIAL_DELAY end # @return [Numeric] Maximum delay in seconds. def max_delay @max_delay || DEFAULT_MAX_DELAY end # @return [Numeric] The delay scaling factor for each subsequent retry attempt. def multiplier @multiplier || DEFAULT_MULTIPLIER end # @return [Array] List of retry codes. def retry_codes @retry_codes || DEFAULT_RETRY_CODES end # @return [Numeric] Timeout threshold value in seconds. def timeout @timeout || DEFAULT_TIMEOUT end ## # Returns a duplicate in a non-executing state, i.e. with the deadline # and current delay reset. # # @return [RetryPolicy] # def dup RetryPolicy.new initial_delay: @initial_delay, max_delay: @max_delay, multiplier: @multiplier, retry_codes: @retry_codes, timeout: @timeout end ## # Perform delay if and only if retriable. # # If positional argument `error` is provided, the retriable logic uses # `retry_codes`. Otherwise, `timeout` is used. # # @return [Boolean] Whether the delay was executed. # def call error = nil should_retry = error.nil? ? retry_with_deadline? : retry_error?(error) return false unless should_retry perform_delay! end alias perform_delay call ## # Perform delay. # # @return [Boolean] Whether the delay was executed. # def perform_delay! delay! increment_delay! @perform_delay_count += 1 true end ## # Current delay value in seconds. # # @return [Numeric] Time delay in seconds. # def delay @delay end ## # Current number of times the delay has been performed # # @return [Integer] # def perform_delay_count @perform_delay_count end ## # Start tracking the deadline and delay by initializing those values. # # This is normally done when the object is constructed, but it can be # done explicitly in order to reinitialize the state in case this # retry policy was created in the past or is being reused. # # @param mock_delay [boolean,Proc] if truthy, delays are "mocked", # meaning they do not actually take time, but are measured as if they # did, which is useful for tests. If set to a Proc, it will be called # whenever a delay would happen, and passed the delay in seconds, # also useful for testing. # def start! mock_delay: false @mock_time = mock_delay ? Process.clock_gettime(Process::CLOCK_MONOTONIC) : nil @mock_delay_callback = mock_delay.respond_to?(:call) ? mock_delay : nil @deadline = cur_time + timeout @delay = initial_delay @perform_delay_count = 0 self end ## # @private # @return [Boolean] Whether this error should be retried. # def retry_error? error (defined?(::GRPC) && error.is_a?(::GRPC::BadStatus) && retry_codes.include?(error.code)) || (error.respond_to?(:response_status) && retry_codes.include?(ErrorCodes.grpc_error_for(error.response_status))) end # @private # @return [Boolean] Whether this policy should be retried based on the deadline. def retry_with_deadline? deadline > cur_time end ## # @private # Apply default values to the policy object. This does not replace user-provided values, # it only overrides empty values. # # @param retry_policy [Hash] The policy for error retry. Keys must match the arguments for # {Gapic::Common::RetryPolicy.new}. # def apply_defaults retry_policy return unless retry_policy.is_a? Hash @retry_codes ||= convert_codes retry_policy[:retry_codes] @initial_delay ||= retry_policy[:initial_delay] @multiplier ||= retry_policy[:multiplier] @max_delay ||= retry_policy[:max_delay] self end # @private Equality test def eql? other other.is_a?(RetryPolicy) && other.initial_delay == initial_delay && other.max_delay == max_delay && other.multiplier == multiplier && other.retry_codes == retry_codes && other.timeout == timeout end alias == eql? # @private Hash code def hash [initial_delay, max_delay, multiplier, retry_codes, timeout].hash end private # @private # @return [Numeric] The performed delay. def delay! if @mock_time @mock_time += delay @mock_delay_callback&.call delay else Kernel.sleep delay end end # @private # @return [Numeric] The new delay in seconds. def increment_delay! @delay = [delay * multiplier, max_delay].min end # @private # @return [Numeric] The deadline for timeout-based policies. def deadline @deadline end # @private # Mockable way to get time. def cur_time @mock_time || Process.clock_gettime(Process::CLOCK_MONOTONIC) end # @private # @return [Array Error codes converted to their respective integer values. def convert_codes input_codes return nil if input_codes.nil? Array(input_codes).map do |obj| case obj when String ErrorCodes::ERROR_STRING_MAPPING[obj] when Integer obj end end.compact end end end end gapic-common-1.2.0/lib/gapic/common/error.rb0000644000004100000410000000130215143460047020712 0ustar www-datawww-data# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "json" module Gapic module Common # Gapic Common exception class class Error < StandardError end end end gapic-common-1.2.0/lib/gapic/common/version.rb0000644000004100000410000000120415143460047021247 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Common VERSION = "1.2.0".freeze end end gapic-common-1.2.0/lib/gapic/common/polling_harness.rb0000644000004100000410000000640215143460047022756 0ustar www-datawww-data# Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common/retry_policy" module Gapic module Common ## # Provides a generic mechanism for periodic polling an operation. # # Polling intervals are calculated from the provided retry policy. # # Supports exponential backoff via `multiplier`, and automatically # retries gRPC errors listed in `retry_codes`. # class PollingHarness # @return [Gapic::Common::RetryPolicy] The retry policy associated with this instance. attr_reader :retry_policy ## # Create new Gapic::Common::PollingHarness instance. # # @param retry_policy [Gapic::Common::RetryPolicy] The retry policy to # use. If not provided, a new retry policy is constructed from the # given kwargs. # @param kwargs [keywords] Keyword arguments used to create a new retry # policy. See {RetryPolicy#initialize}. # def initialize retry_policy: nil, **kwargs @retry_policy = retry_policy ? retry_policy.dup : RetryPolicy.new(**kwargs) end ## # Perform polling with exponential backoff. Repeatedly calls the given # block until it returns a result other than the given sentinel value # (normally `nil`), then returns that final result. # # Uses the retry policy regulate retries, including delays between tries, # retriable errors, and final timeout. If an error code other than those # listed in {RetryPolicy#retry_codes} is raised, it is propagated out. If # the timeout expires, the given timeout result (normally `nil`) is # returned. # # @param wait_sentinel [Object] The return value that should signal the # polling harness to continue waiting. Any other value is treated as # a real result and returned. Defaults to `nil`. # @param timeout_result [Object] The result to return if timeout occurs. # Defaults to `nil`. # # @yieldreturn [Object] The result of the polling logic, either a result # to return, or the `wait_sentinel` value. # def wait wait_sentinel: nil, timeout_result: nil, mock_delay: false unless block_given? raise ArgumentError, "No callback provided to wait method." end retry_policy.start! mock_delay: mock_delay loop do begin response = yield return response unless response == wait_sentinel rescue StandardError => e # Currently retry_error only accounts for ::GRPC::BadStatus. raise unless retry_policy.retry_error? e end retry_policy.perform_delay! return timeout_result unless retry_policy.retry_with_deadline? end end end end end gapic-common-1.2.0/lib/gapic/common/error_codes.rb0000644000004100000410000000426415143460047022101 0ustar www-datawww-data# Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Common ## # @private # The gRPC error codes and their HTTP mapping # module ErrorCodes # @private # See https://grpc.github.io/grpc/core/md_doc_statuscodes.html for a # list of error codes. error_code_mapping = [ "OK", "CANCELLED", "UNKNOWN", "INVALID_ARGUMENT", "DEADLINE_EXCEEDED", "NOT_FOUND", "ALREADY_EXISTS", "PERMISSION_DENIED", "RESOURCE_EXHAUSTED", "FAILED_PRECONDITION", "ABORTED", "OUT_OF_RANGE", "UNIMPLEMENTED", "INTERNAL", "UNAVAILABLE", "DATA_LOSS", "UNAUTHENTICATED" ].freeze # @private ERROR_STRING_MAPPING = error_code_mapping.each_with_index.to_h.freeze # @private HTTP_GRPC_CODE_MAP = { 400 => 3, # InvalidArgumentError 401 => 16, # UnauthenticatedError 403 => 7, # PermissionDeniedError 404 => 5, # NotFoundError 409 => 6, # AlreadyExistsError 412 => 9, # FailedPreconditionError 429 => 8, # ResourceExhaustedError 499 => 1, # CanceledError 500 => 13, # InternalError 501 => 12, # UnimplementedError 503 => 14, # UnavailableError 504 => 4 # DeadlineExceededError }.freeze # @private # Converts http error codes into corresponding gRPC ones def self.grpc_error_for http_error_code return 2 unless http_error_code # The http status codes mapped to their error classes. HTTP_GRPC_CODE_MAP[http_error_code] || 2 # UnknownError end end end end gapic-common-1.2.0/lib/gapic/common.rb0000644000004100000410000000205715143460047017571 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc/errors" require "grpc/core/status_codes" require "gapic/common/error" require "gapic/common/polling_harness" require "gapic/call_options" require "gapic/headers" require "gapic/operation" require "gapic/paged_enumerable" require "gapic/protobuf" require "gapic/stream_input" require "gapic/common/version" # Gapic is Google's API client generator module Gapic # The gapic-common gem includes various common libraries for clients built # with Gapic. module Common end end gapic-common-1.2.0/lib/gapic/call_options/0000755000004100000410000000000015143460047020436 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/call_options/retry_policy.rb0000644000004100000410000000261015143460047023506 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common/retry_policy" module Gapic class CallOptions ## # The policy for retrying failed RPC calls using an incremental backoff. A new object instance # should be used for every RpcCall invocation. # # Only errors originating from GRPC will be retried. # class RetryPolicy < Gapic::Common::RetryPolicy ## # Create new API Call RetryPolicy. # # @param retry_codes [Array] List of retry codes. # @param initial_delay [Numeric] Initial delay in seconds. # @param multiplier [Numeric] The delay scaling factor for each subsequent retry attempt. # @param max_delay [Numeric] Maximum delay in seconds. # def initialize retry_codes: nil, initial_delay: nil, multiplier: nil, max_delay: nil super end end end end gapic-common-1.2.0/lib/gapic/call_options/error_codes.rb0000644000004100000410000000116115143460047023270 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # File moved. require "gapic/common/error_codes" gapic-common-1.2.0/lib/gapic/headers.rb0000644000004100000410000000570315143460047017715 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/operation/retry_policy" require "google/protobuf/well_known_types" require "gapic/common/version" module Gapic # A collection of common header values. module Headers # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity ## # @param ruby_version [String] The ruby version. Defaults to `RUBY_VERSION`. # @param lib_name [String] The client library name. # @param lib_version [String] The client library version. # @param gax_version [String] The Gapic version. Defaults to `Gapic::Common::VERSION`. # @param gapic_version [String] The Gapic version. # @param grpc_version [String] The GRPC version. Defaults to `::GRPC::VERSION`. # @param rest_version [String] The Rest Library (Faraday) version. Defaults to `Faraday::VERSION`. # @param transports_version_send [Array] Which transports to send versions for. # Allowed values to contain are: # `:grpc` to send the GRPC library version (if defined) # `:rest` to send the REST library version (if defined) # Defaults to `[:grpc]` # def self.x_goog_api_client ruby_version: nil, lib_name: nil, lib_version: nil, gax_version: nil, gapic_version: nil, grpc_version: nil, rest_version: nil, protobuf_version: nil, transports_version_send: [:grpc] ruby_version ||= ::RUBY_VERSION gax_version ||= ::Gapic::Common::VERSION grpc_version ||= ::GRPC::VERSION if defined? ::GRPC::VERSION rest_version ||= ::Faraday::VERSION if defined? ::Faraday::VERSION protobuf_version ||= Gem.loaded_specs["google-protobuf"].version.to_s if Gem.loaded_specs.key? "google-protobuf" x_goog_api_client_header = ["gl-ruby/#{ruby_version}"] x_goog_api_client_header << "#{lib_name}/#{lib_version}" if lib_name x_goog_api_client_header << "gax/#{gax_version}" x_goog_api_client_header << "gapic/#{gapic_version}" if gapic_version x_goog_api_client_header << "grpc/#{grpc_version}" if grpc_version && transports_version_send.include?(:grpc) x_goog_api_client_header << "rest/#{rest_version}" if rest_version && transports_version_send.include?(:rest) x_goog_api_client_header << "pb/#{protobuf_version}" if protobuf_version x_goog_api_client_header.join " ".freeze end end # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity end gapic-common-1.2.0/lib/gapic/operation/0000755000004100000410000000000015143460047017750 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/operation/retry_policy.rb0000644000004100000410000000373315143460047023027 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common/retry_policy" module Gapic class Operation ## # The policy for retrying operation reloads using an incremental backoff. # # A new object instance should be used for every Operation invocation. # class RetryPolicy < Gapic::Common::RetryPolicy # @return [Numeric] Default initial delay in seconds. DEFAULT_INITIAL_DELAY = 10 # @return [Numeric] Default maximum delay in seconds. DEFAULT_MAX_DELAY = 300 # Five minutes # @return [Numeric] Default delay scaling factor for subsequent retry attempts. DEFAULT_MULTIPLIER = 1.3 # @return [Numeric] Default timeout threshold value in seconds. DEFAULT_TIMEOUT = 3600 # One hour ## # Create new Operation RetryPolicy. # # @param initial_delay [Numeric] Initial delay in seconds. # @param multiplier [Numeric] The delay scaling factor for each subsequent retry attempt. # @param max_delay [Numeric] Maximum delay in seconds. # @param timeout [Numeric] Timeout threshold value in seconds. # def initialize initial_delay: nil, multiplier: nil, max_delay: nil, timeout: nil super( initial_delay: initial_delay || DEFAULT_INITIAL_DELAY, max_delay: max_delay || DEFAULT_MAX_DELAY, multiplier: multiplier || DEFAULT_MULTIPLIER, timeout: timeout || DEFAULT_TIMEOUT ) end end end end gapic-common-1.2.0/lib/gapic/universe_domain_concerns.rb0000644000004100000410000000531015143460047023355 0ustar www-datawww-data# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common/error" module Gapic ## # A mixin module that provides methods for obtaining the effective universe # domain, endpoint, and credentials for a stub. This is included in # Grpc::ServiceStub and Rest::ClientStub. # module UniverseDomainConcerns ## # A substitution string for the universe domain in an endpoint template # @return [String] # ENDPOINT_SUBSTITUTION = "$UNIVERSE_DOMAIN$".freeze ## # The effective endpoint # @return [String] # attr_reader :endpoint ## # The effective universe domain # @return [String] # attr_reader :universe_domain ## # The effective credentials # # @return [Google::Auth::Credentials, Signet::OAuth2::Client, Proc, # ::GRPC::Core::Channel, ::GRPC::Core::ChannelCredentials] # attr_reader :credentials protected ## # @private # Called from the stub constructor to populate the data. # def setup_universe_domain universe_domain: nil, endpoint: nil, endpoint_template: nil, credentials: nil raise ArgumentError, "endpoint or endpoint_template is required" if endpoint.nil? && endpoint_template.nil? raise ArgumentError, "credentials is required" if credentials.nil? universe_domain ||= ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com" endpoint ||= endpoint_template.sub ENDPOINT_SUBSTITUTION, universe_domain if !(credentials.respond_to?(:disable_universe_domain_check) && credentials.disable_universe_domain_check) && credentials.respond_to?(:universe_domain) && credentials.universe_domain != universe_domain raise UniverseDomainMismatch, "Universe domain is #{universe_domain} but credentials are in #{credentials.universe_domain}" end @universe_domain = universe_domain @endpoint = endpoint @credentials = credentials end end ## # Raised when the configured universe domain does not match the universe # domain of the credentials. # class UniverseDomainMismatch < ::Gapic::Common::Error end end gapic-common-1.2.0/lib/gapic/generic_lro/0000755000004100000410000000000015143460047020240 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/generic_lro/operation.rb0000644000004100000410000002777715143460047022611 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/generic_lro/base_operation" require "gapic/operation/retry_policy" module Gapic module GenericLRO ## # A class used to wrap the longrunning operation objects, including the nonstandard ones # (`nonstandard` meaning not conforming to the AIP-151). # It provides helper methods to poll and check for status of these operations. # class Operation < Gapic::GenericLRO::BaseOperation ## # @param operation [Object] The long-running operation object that is returned by the initial method call. # # @param client [Object] The client that handles the polling for the longrunning operation. # # @param polling_method_name [String] The name of the methods on the client that polls the longrunning operation. # # @param operation_status_field [String] The name of the `status` field in the underlying long-running operation # object. The `status` field signals that the operation has finished. It should either contain symbols, and # be set to `:DONE` when finished or contain a boolean and be set to `true` when finished. # # @param request_values [Map] The values that are to be copied from the request that # triggered the longrunning operation, into the request that polls for the longrunning operation. # The format is `name of the request field` -> `value` # # @param operation_name_field [String, nil] The name of the `name` field in the underlying long-running operation # object. Optional. # # @param operation_err_field [String, nil] The name of the `error` field in the underlying long-running operation # object. The `error` field should be a message-type, and have same semantics as `google.rpc.Status`, including # an integer `code` subfield, that carries an error code. If the `operation_err_field` field is given, # the `operation_err_code_field` and `operation_err_msg_field` parameters are ignored. Optional. # # @param operation_err_code_field [String, nil] The name of the `error_code` field in the underlying # long-running operation object. It is ignored if `operation_err_field` is given. Optional. # # @param operation_err_msg_field [String, nil] The name of the `error_message` field in the underlying # long-running operation object. It is ignored if `operation_err_field` is given. Optional. # # @param operation_copy_fields [Map] The map of the fields that need to be copied from the # long-running operation object that the polling method returns to the polling request. # The format is `name of the operation object field` -> `name of the request field` (`from` -> `to`) # # @param options [Gapic::CallOptions] call options for this operation # def initialize operation, client:, polling_method_name:, operation_status_field:, request_values: {}, operation_name_field: nil, operation_err_field: nil, operation_err_code_field: nil, operation_err_msg_field: nil, operation_copy_fields: {}, options: {} @client = client @polling_method_name = polling_method_name @operation_status_field = operation_status_field @request_values = request_values || {} @operation_name_field = operation_name_field @operation_err_field = operation_err_field @operation_err_code_field = operation_err_code_field @operation_err_msg_field = operation_err_msg_field @operation_copy_fields = operation_copy_fields || {} @on_done_callbacks = [] @on_reload_callbacks = [] @options = options || {} super operation end ## # If the operation is done, returns the response. If the operation response is an error, the error will be # returned. Otherwise returns nil. # # @return [Object, nil] The result of the operation or an error. # def results return error if error? response if response? end ## # Returns the name of the operation, if specified. # # @return [String, nil] The name of the operation. # def name return nil if @operation_name_field.nil? operation.send @operation_name_field if operation.respond_to? @operation_name_field end ## # Checks if the operation is done. This does not send a new api call, but checks the result of the previous api # call to see if done. # # @return [Boolean] Whether the operation is done. # def done? return status if [true, false].include? status status == :DONE end ## # Checks if the operation is done and the result is not an error. If the operation is not finished then this will # return false. # # @return [Boolean] Whether a response has been returned. # def response? done? && !error? end ## # If the operation is completed successfully, returns the underlying operation object, otherwise returns nil. # # @return [Object, nil] The response of the operation. def response operation if response? end ## # Checks if the operation is done and the result is an error. If the operation is not finished then this will # return false. # # @return [Boolean] Whether an error has been returned. # def error? no_error_code = error_code.nil? || error_code.zero? done? && !(err.nil? && no_error_code) end ## # If the operation response is an error, the error will be returned, otherwise returns nil. # # @return [Object, nil] The error object. # def error return unless error? err || GenericError.new(error_code, error_msg) end ## # Reloads the operation object. # # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided # to customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. # # @return [Gapic::GenericLRO::Operation] Since this method changes internal state, it returns itself. # def reload! options: nil return self if done? @on_reload_callbacks.each { |proc| proc.call self } request_hash = @request_values.transform_keys(&:to_sym) @operation_copy_fields.each do |field_from, field_to| request_hash[field_to.to_sym] = operation.send field_from.to_s if operation.respond_to? field_from.to_s end options = merge_options options, @options ops = @client.send @polling_method_name, request_hash, options ops = ops.operation if ops.is_a? Gapic::GenericLRO::BaseOperation self.operation = ops if done? @on_reload_callbacks.clear @on_done_callbacks.each { |proc| proc.call self } @on_done_callbacks.clear end self end alias refresh! reload! ## # Blocking method to wait until the operation has completed or the maximum timeout has been reached. Upon # completion, registered callbacks will be called, then - if a block is given - the block will be called. # # @param retry_policy [RetryPolicy, Hash, Proc] The policy for retry. A custom proc that takes the error as an # argument and blocks can also be provided. # # @yieldparam operation [Gapic::GenericLRO::Operation] Yields the finished Operation. # def wait_until_done! retry_policy: nil retry_policy = ::Gapic::Operation::RetryPolicy.new(**retry_policy) if retry_policy.is_a? Hash retry_policy ||= ::Gapic::Operation::RetryPolicy.new until done? reload! break unless retry_policy.call end yield self if block_given? self end ## # Registers a callback to be run when an operation is being reloaded. If the operation has completed # prior to a call to this function the callback will NOT be called or registered. # # @yieldparam operation [Gapic::Operation] Yields the finished Operation. # def on_reload &block return if done? @on_reload_callbacks.push block end ## # Registers a callback to be run when a refreshed operation is marked as done. If the operation has completed # prior to a call to this function the callback will be called instead of registered. # # @yieldparam operation [Gapic::Operation] Yields the finished Operation. # def on_done &block if done? yield self else @on_done_callbacks.push block end end private ## # @return [String, Boolean, nil] A status, whether operation is Done, # as either a boolean (`true` === Done) or a symbol (`:DONE` === Done) # def status return nil if @operation_status_field.nil? operation.send @operation_status_field end ## # @return [String, nil] An error message if the error message field is specified # def err return nil if @operation_err_field.nil? operation.send @operation_err_field if operation.respond_to? @operation_err_field end ## # @return [String, nil] An error code if the error code field is specified # def error_code return nil if @operation_err_code_field.nil? operation.send @operation_err_code_field if operation.respond_to? @operation_err_code_field end ## # @return [String, nil] An error message if the error message field is specified # def error_msg return nil if @operation_err_msg_field.nil? operation.send @operation_err_msg_field if operation.respond_to? @operation_err_msg_field end ## # Merges options given to the method with a baseline Gapic::Options object # # @param method_opts [Gapic::CallOptions, Hash] The options for making the RPC call given to a method invocation. # A Hash can be provided to customize the options object, using keys that match the arguments # for {Gapic::CallOptions.new}. # # @param baseline_opts [Gapic::CallOptions, Hash] The baseline options for making the RPC call. # A Hash can be provided to customize the options object, using keys that match the arguments # for {Gapic::CallOptions.new}. # def merge_options method_opts, baseline_opts options = if method_opts.respond_to? :to_h method_opts.to_h.merge baseline_opts.to_h else baseline_opts.to_h end Gapic::CallOptions.new(**options) end ## # Represents a generic error that a generic LRO can report # # @!attribute [r] code # @return [String] An error code # # @!attribute [r] message # @return [String] An error message # class GenericError attr_accessor :code attr_accessor :message ## # @param code [String] An error code # @param message [String] An error message def initialize code, message @code = code @message = message end end protected ## # @private # @return [Object] The client that handles the polling for the longrunning operation. attr_accessor :client end end end gapic-common-1.2.0/lib/gapic/generic_lro/base_operation.rb0000644000004100000410000000205615143460047023562 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module GenericLRO ## # A base class for the wrappers over the long-running operations. # # @attribute [r] operation # @return [Object] The wrapped operation object. # class BaseOperation attr_reader :operation ## # @private # @param operation [Object] The operation object to be wrapped def initialize operation @operation = operation end protected attr_writer :operation end end end gapic-common-1.2.0/lib/gapic/operation.rb0000644000004100000410000002267115143460047020305 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/operation/retry_policy" require "google/protobuf/well_known_types" module Gapic # A class used to wrap Google::Longrunning::Operation objects. This class provides helper methods to check the # status of an Operation # # @example Checking Operation status # # this example assumes both api_client and operations_client # # already exist. # require "gapic/operation" # # op = Gapic::Operation.new( # api_client.method_that_returns_longrunning_operation(), # operations_client, # Google::Example::ResultType, # Google::Example::MetadataType # ) # # op.done? # => false # op.reload! # => operation completed # # if op.done? # results = op.results # handle_error(results) if op.error? # # Handle results. # end # # @example Working with callbacks # # this example assumes both api_client and operations_client # # already exist. # require "gapic/operation" # # op = Gapic::Operation.new( # api_client.method_that_returns_longrunning_operation(), # operations_client, # Google::Example::ResultType, # Google::Example::MetadataType # ) # # # Register a callback to be run when an operation is done. # op.on_done do |operation| # raise operation.results.message if operation.error? # # process(operation.results) # # process(operation.metadata) # end # # # Reload the operation running callbacks if operation completed. # op.reload! # # # Or block until the operation completes, passing a block to be called # # on completion. # op.wait_until_done! do |operation| # raise operation.results.message if operation.error? # # process(operation.results) # # process(operation.rmetadata) # end # # @attribute [r] grpc_op # @return [Google::Longrunning::Operation] The wrapped grpc # operation object. class Operation attr_reader :grpc_op ## # @param grpc_op [Google::Longrunning::Operation] The inital longrunning operation. # @param client [Google::Longrunning::OperationsClient] The client that handles the grpc operations. # @param result_type [Class] The class type to be unpacked from the result. If not provided the class type will be # looked up. Optional. # @param metadata_type [Class] The class type to be unpacked from the metadata. If not provided the class type # will be looked up. Optional. # @param options [Gapic::CallOptions] call options for this operation # def initialize grpc_op, client, result_type: nil, metadata_type: nil, options: {} @grpc_op = grpc_op @client = client @result_type = result_type @metadata_type = metadata_type @on_done_callbacks = [] @options = options end ## # If the operation is done, returns the response. If the operation response is an error, the error will be # returned. Otherwise returns nil. # # @return [Object, Google::Rpc::Status, nil] The result of the operation. If it is an error a # `Google::Rpc::Status` will be returned. def results return error if error? response if response? end ## # Returns the server-assigned name of the operation, which is only unique within the same service that originally # returns it. If you use the default HTTP mapping, the name should have the format of operations/some/unique/name. # # @return [String] The name of the operation. # def name @grpc_op.name end ## # Returns the metadata of an operation. If a type is provided, the metadata will be unpacked using the type # provided; returning nil if the metadata is not of the type provided. If the type is not of provided, the # metadata will be unpacked using the metadata's type_url if the type_url is found in the # `Google::Protobuf::DescriptorPool.generated_pool`. If the type cannot be found the raw metadata is retuned. # # @return [Object, nil] The metadata of the operation. Can be nil. # def metadata return if @grpc_op.metadata.nil? return @grpc_op.metadata.unpack @metadata_type if @metadata_type descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup @grpc_op.metadata.type_name return @grpc_op.metadata.unpack descriptor.msgclass if descriptor @grpc_op.metadata end ## # Checks if the operation is done. This does not send a new api call, but checks the result of the previous api # call to see if done. # # @return [Boolean] Whether the operation is done. # def done? @grpc_op.done end ## # Checks if the operation is done and the result is a response. If the operation is not finished then this will # return false. # # @return [Boolean] Whether a response has been returned. # def response? done? ? @grpc_op.result == :response : false end ## # If the operation is done, returns the response, otherwise returns nil. # # @return [Object, nil] The response of the operation. def response return unless response? return @grpc_op.response.unpack @result_type if @result_type descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup @grpc_op.response.type_name return @grpc_op.response.unpack descriptor.msgclass if descriptor @grpc_op.response end ## # Checks if the operation is done and the result is an error. If the operation is not finished then this will # return false. # # @return [Boolean] Whether an error has been returned. # def error? done? ? @grpc_op.result == :error : false end ## # If the operation response is an error, the error will be returned, otherwise returns nil. # # @return [Google::Rpc::Status, nil] The error object. # def error @grpc_op.error if error? end ## # Cancels the operation. # # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize # the options object, using keys that match the arguments for {Gapic::CallOptions.new}. # def cancel options: nil # Converts hash and nil to an options object options = Gapic::CallOptions.new(**options.to_h) if options.respond_to? :to_h @client.cancel_operation({ name: @grpc_op.name }, options) end ## # Deletes the operation. # # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize # the options object, using keys that match the arguments for {Gapic::CallOptions.new}. # def delete options: nil # Converts hash and nil to an options object options = Gapic::CallOptions.new(**options.to_h) if options.respond_to? :to_h @client.delete_operation({ name: @grpc_op.name }, options) end ## # Reloads the operation object. # # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize # the options object, using keys that match the arguments for {Gapic::CallOptions.new}. # # @return [Gapic::Operation] Since this method changes internal state, it returns itself. # def reload! options: nil options = if options.respond_to? :to_h options.to_h.merge @options.to_h else @options.to_h end options = Gapic::CallOptions.new(**options) gax_op = @client.get_operation({ name: @grpc_op.name }, options) @grpc_op = gax_op.grpc_op if done? @on_done_callbacks.each { |proc| proc.call self } @on_done_callbacks.clear end self end alias refresh! reload! ## # Blocking method to wait until the operation has completed or the maximum timeout has been reached. Upon # completion, registered callbacks will be called, then - if a block is given - the block will be called. # # @param retry_policy [RetryPolicy, Hash, Proc] The policy for retry. A custom proc that takes the error as an # argument and blocks can also be provided. # # @yieldparam operation [Gapic::Operation] Yields the finished Operation. # def wait_until_done! retry_policy: nil retry_policy = RetryPolicy.new(**retry_policy) if retry_policy.is_a? Hash retry_policy ||= RetryPolicy.new until done? reload! break unless retry_policy.call end yield self if block_given? self end ## # Registers a callback to be run when a refreshed operation is marked as done. If the operation has completed # prior to a call to this function the callback will be called instead of registered. # # @yieldparam operation [Gapic::Operation] Yields the finished Operation. # def on_done &block if done? yield self else @on_done_callbacks.push block end end end end gapic-common-1.2.0/lib/gapic/logging_concerns.rb0000644000004100000410000001416515143460047021624 0ustar www-datawww-data# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "google/cloud/env" require "google/logging/message" require "google/logging/structured_formatter" module Gapic ## # A mixin module that handles logging setup for a stub. # module LoggingConcerns ## # The logger for this object. # # @return [Logger] # attr_reader :logger ## # @private # A convenience object used by stub-based logging. # class StubLogger OMIT_FILES = [ /^#{Regexp.escape __dir__}/ ].freeze def initialize logger: nil, **kwargs @logger = logger @kwargs = kwargs end def enabled? !!@logger end def log severity return unless @logger locations = caller_locations @logger.add severity do builder = LogEntryBuilder.new(**@kwargs) builder.set_source_location_from locations yield builder builder.build rescue StandardError # Do nothing end end def info(&) log(Logger::INFO, &) end def debug(&) log(Logger::DEBUG, &) end ## # @private # Builder for a log entry, passed to {StubLogger#log}. # class LogEntryBuilder def initialize system_name: nil, service: nil, endpoint: nil, client_id: nil @system_name = system_name @service = service @endpoint = endpoint @client_id = client_id @message = nil @caller_locations = caller_locations @fields = { "clientId" => @client_id } end attr_reader :system_name attr_reader :service attr_reader :endpoint attr_accessor :message attr_writer :source_location attr_reader :fields def set name, value fields[name] = value end def set_system_name set "system", system_name end def set_service set "serviceName", service end def set_credentials_fields creds creds = creds.client if creds.respond_to? :client set "credentialsId", creds.object_id set "credentialsType", creds.class.name set "credentialsScope", creds.scope if creds.respond_to? :scope set "useSelfSignedJWT", creds.enable_self_signed_jwt? if creds.respond_to? :enable_self_signed_jwt? set "universeDomain", creds.universe_domain if creds.respond_to? :universe_domain end def source_location @source_location ||= Google::Logging::SourceLocation.for_caller omit_files: OMIT_FILES, locations: @caller_locations end def set_source_location_from locations @caller_locations = locations @source_location = nil end def build Google::Logging::Message.from message: message, source_location: source_location, fields: fields end end end ## # @private # Initialize logging concerns. # def setup_logging logger: :default, stream: nil, formatter: nil, level: nil, system_name: nil, service: nil, endpoint: nil, client_id: nil service = LoggingConcerns.normalize_service service system_name = LoggingConcerns.normalize_system_name system_name logging_env = ENV["GOOGLE_SDK_RUBY_LOGGING_GEMS"].to_s.downcase logger = nil if ["false", "none"].include? logging_env if logger == :default logger = nil if ["true", "all"].include?(logging_env) || logging_env.split(",").include?(system_name) stream ||= $stderr level ||= "DEBUG" formatter ||= Google::Logging::StructuredFormatter.new if Google::Cloud::Env.get.logging_agent_expected? logger = Logger.new stream, progname: system_name, level: level, formatter: formatter end end @logger = logger @stub_logger = StubLogger.new logger: logger, system_name: system_name, service: service, endpoint: endpoint, client_id: client_id end # @private attr_reader :stub_logger class << self # @private def random_uuid4 ary = Random.bytes 16 ary.setbyte 6, ((ary.getbyte(6) & 0x0f) | 0x40) ary.setbyte 8, ((ary.getbyte(8) & 0x3f) | 0x80) ary.unpack("H8H4H4H4H12").join "-" end # @private def normalize_system_name input case input when String input when Class input.name.split("::")[..-3] .map { |elem| elem.scan(/[A-Z][A-Z]*(?=[A-Z][a-z0-9]|$)|[A-Z][a-z0-9]+/).map(&:downcase).join("_") } .join("-") else "googleapis" end end # @private def normalize_service input case input when String input when Class mod = input.name.split("::")[..-2].inject(Object) { |m, n| m.const_get n } if mod.const_defined? "Service" mod.const_get("Service").service_name else name_segments = input.name.split("::")[..-3] mod = name_segments.inject(Object) { |m, n| m.const_get n } name_segments.join "." if mod.const_defined? "Rest" end end end end end end gapic-common-1.2.0/lib/gapic/lru_hash.rb0000644000004100000410000000441415143460047020105 0ustar www-datawww-data# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic ## # @private # # Linked list based hash maintaining the order of # access/creation of the keys. # class LruHash def initialize size = 1 raise ArgumentError, "The size of LRU hash can't be < 1" unless size > 1 @start = nil @end = nil @size = size @cache = {} end def get key return nil unless @cache.key? key node = @cache[key] move_to_top node node.value end def put key, value if @cache.key? key node = @cache[key] node.value = value move_to_top node else remove_tail if @cache.size >= @size new_node = Node.new key, value insert_at_top new_node @cache[key] = new_node end end private def move_to_top node return if node.equal? @start if node.equal? @end @end = node.prev @end.next = nil else node.prev.next = node.next node.next.prev = node.prev end node.prev = nil node.next = @start @start.prev = node @start = node end def remove_tail @cache.delete @end.key @end = @end.prev @end.next = nil if @end end def insert_at_top node if @start.nil? @start = node @end = node else node.next = @start @start.prev = node @start = node end end ## # @private # # Node class for linked list. # class Node attr_accessor :key attr_accessor :value attr_accessor :prev attr_accessor :next def initialize key, value @key = key @value = value @prev = nil @next = nil end end end end gapic-common-1.2.0/lib/gapic/call_options.rb0000644000004100000410000000706315143460047020771 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/call_options/retry_policy" require "gapic/common/error_codes" module Gapic ## # Encapsulates the overridable settings for a particular RPC call. # # @!attribute [r] timeout # @return [Numeric, nil] # @!attribute [r] metadata # @return [Hash] # @!attribute [r] retry_policy # @return [RetryPolicy, Object] # class CallOptions attr_reader :timeout attr_reader :metadata attr_reader :retry_policy ## # Create a new Options object instance. # # @param timeout [Numeric] The client-side timeout for RPC calls. # @param metadata [Hash] The request header params. # @param retry_policy [Hash, RetryPolicy, Proc] The policy for error retry. A Hash can be provided to # customize the policy object, using keys that match the arguments for {RetryPolicy.initialize}. # # A Proc object can also be provided. The Proc should accept an error as an argument, and return `true` if the # error should be retried or `false` if not. If the error is to be retried, the Proc object must also block # with an incremental delay before returning `true`. # def initialize timeout: nil, metadata: nil, retry_policy: nil # Converts hash and nil to a policy object retry_policy = RetryPolicy.new(**retry_policy.to_h) if retry_policy.respond_to? :to_h @timeout = timeout # allow to be nil so it can be overridden @metadata = metadata.to_h # Ensure always hash, even for nil @retry_policy = retry_policy end ## # @private # Apply default values to the options object. This does not replace user-provided values, it only overrides # empty values. # # @param timeout [Numeric] The client-side timeout for RPC calls. # @param metadata [Hash] the request header params. # @param retry_policy [Hash] The policy for error retry. keys must match the arguments for # {RetryPolicy.initialize}. # def apply_defaults timeout: nil, metadata: nil, retry_policy: nil @timeout ||= timeout @metadata = metadata.merge @metadata if metadata @retry_policy.apply_defaults retry_policy if @retry_policy.respond_to? :apply_defaults end ## # Convert to hash form. # # @return [Hash] # def to_h { timeout: timeout, metadata: metadata, retry_policy: retry_policy } end ## # Return a new CallOptions with the given modifications. The current object # is not modified. # # @param kwargs [keywords] Updated fields. See {#initialize} for details. # @return [CallOptions] A new CallOptions object. # def merge **kwargs kwargs = to_h.merge kwargs CallOptions.new(**kwargs) end # @private Equality test def eql? other other.is_a?(CallOptions) && other.timeout == timeout && other.metadata == metadata && other.retry_policy == retry_policy end alias == eql? # @private Hash code def hash to_h.hash end end end gapic-common-1.2.0/lib/gapic/grpc.rb0000644000004100000410000000126115143460047017230 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "grpc" require "gapic/grpc/errors" require "gapic/grpc/service_stub" require "gapic/grpc/status_details" gapic-common-1.2.0/lib/gapic/rest.rb0000644000004100000410000000220315143460047017247 0ustar www-datawww-data# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## # Rest GAPIC features are still under development. # require "faraday" require "gapic/call_options" require "gapic/common/version" require "gapic/headers" require "gapic/protobuf" require "gapic/rest/client_stub" require "gapic/rest/error" require "gapic/rest/faraday_middleware" require "gapic/rest/grpc_transcoder" require "gapic/rest/http_binding_override_configuration" require "gapic/rest/operation" require "gapic/rest/paged_enumerable" require "gapic/rest/server_stream" require "gapic/rest/threaded_enumerator" require "gapic/rest/transport_operation" require "json" gapic-common-1.2.0/lib/gapic/config/0000755000004100000410000000000015143460047017215 5ustar www-datawww-datagapic-common-1.2.0/lib/gapic/config/method.rb0000644000004100000410000000372115143460047021025 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic module Config ## # Config::Method is a configuration class that represents the configuration for an API RPC call. # # @example # require "gapic/config" # # class ServiceConfig # extend Gapic::Config # # config_attr :host, "localhost", String # config_attr :port, 443, Integer # config_attr :timeout, nil, Numeric, nil # config_attr :metadata, nil, Hash, nil # # attr_reader :rpc_method # # def initialize parent_config = nil # @parent_config = parent_config unless parent_config.nil? # @rpc_method = Gapic::Config::Method.new # # yield self if block_given? # end # end # # config = ServiceConfig.new # # config.timeout = 60 # config.rpc_method.timeout = 120 # class Method extend Gapic::Config config_attr :timeout, nil, Numeric, nil config_attr :metadata, nil, Hash, nil config_attr :retry_policy, nil, Hash, Proc, nil ## # Create a new Config::Method object instance. # # @param parent_method [Gapic::Config::Method, nil] The config to look to values for. # def initialize parent_method = nil @parent_config = parent_method unless parent_method.nil? yield self if block_given? end end end end gapic-common-1.2.0/lib/gapic/paged_enumerable.rb0000644000004100000410000001745015143460047021563 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Gapic ## # A class to provide the Enumerable interface to the response of a paginated method. PagedEnumerable assumes # response message holds a list of resources and the token to the next page. # # PagedEnumerable provides the enumerations over the resource data, and also provides the enumerations over the # pages themselves. # # @example normal iteration over resources. # paged_enumerable.each { |resource| puts resource } # # @example per-page iteration. # paged_enumerable.each_page { |page| puts page } # # @example Enumerable over pages. # paged_enumerable.each_page do |page| # page.each { |resource| puts resource } # end # # @example more exact operations over pages. # while some_condition() # page = paged_enumerable.page # do_something(page) # break if paged_enumerable.next_page? # paged_enumerable.next_page # end # class PagedEnumerable include Enumerable ## # @attribute [r] page # @return [Page] The current page object. attr_reader :page ## # @private # @param grpc_stub [Gapic::GRPC::Stub] The Gapic gRPC stub object. # @param method_name [Symbol] The RPC method name. # @param request [Object] The request object. # @param response [Object] The response object. # @param operation [::GRPC::ActiveCall::Operation] The RPC operation for the response. # @param options [Gapic::CallOptions] The options for making the RPC call. # @param format_resource [Proc] A Proc object to format the resource object. The Proc should accept response as an # argument, and return a formatted resource object. Optional. # def initialize grpc_stub, method_name, request, response, operation, options, format_resource: nil @grpc_stub = grpc_stub @method_name = method_name @request = request @response = response @options = options @format_resource = format_resource @resource_field = nil # will be set in verify_response! verify_request! verify_response! @page = Page.new @response, @resource_field, operation, format_resource: @format_resource end ## # Iterate over the resources. # # @yield [Object] Gives the resource objects in the stream. # # @raise [RuntimeError] if it's not started yet. # def each &block return enum_for :each unless block_given? each_page do |page| page.each(&block) end end ## # Iterate over the pages. # # @yield [Page] Gives the pages in the stream. # # @raise if it's not started yet. # def each_page return enum_for :each_page unless block_given? loop do break if @page.nil? yield @page next_page! end end ## # True if it has the next page. # def next_page? @page.next_page_token? end ## # Update the response in the current page. # # @return [Page] the new page object. # def next_page! unless next_page? @page = nil return @page end next_request = @request.dup next_request.page_token = @page.next_page_token @grpc_stub.call_rpc @method_name, next_request, options: @options do |next_response, next_operation| @page = Page.new next_response, @resource_field, next_operation, format_resource: @format_resource end @page end alias next_page next_page! ## # The page token to be used for the next RPC call. # # @return [String] # def next_page_token @page.next_page_token end ## # The current response object, for the current page. # # @return [Object] # def response @page.response end private def verify_request! page_token = @request.class.descriptor.find do |f| f.name == "page_token" && f.type == :string end raise ArgumentError, "#{@request.class} must have a page_token field (String)" if page_token.nil? page_size = @request.class.descriptor.find do |f| f.name == "page_size" && [:int32, :int64].include?(f.type) end return unless page_size.nil? raise ArgumentError, "#{@request.class} must have a page_size field (Integer)" end def verify_response! next_page_token = @response.class.descriptor.find do |f| f.name == "next_page_token" && f.type == :string end raise ArgumentError, "#{@response.class} must have a next_page_token field (String)" if next_page_token.nil? # Find all repeated FieldDescriptors on the response Descriptor fields = @response.class.descriptor.select do |f| f.label == :repeated && f.type == :message end repeated_field = fields.first raise ArgumentError, "#{@response.class} must have one repeated field" if repeated_field.nil? min_repeated_field_number = fields.map(&:number).min if min_repeated_field_number != repeated_field.number raise ArgumentError, "#{@response.class} must have one primary repeated field by both position and number" end # We have the correct repeated field, save the field's name @resource_field = repeated_field.name end ## # A class to represent a page in a PagedEnumerable. This also implements Enumerable, so it can iterate over the # resource elements. # # @attribute [r] response # @return [Object] the response object for the page. # @attribute [r] operation # @return [::GRPC::ActiveCall::Operation] the RPC operation for the page. class Page include Enumerable attr_reader :response attr_reader :operation ## # @private # @param response [Object] The response object for the page. # @param resource_field [String] The name of the field in response which holds the resources. # @param operation [::GRPC::ActiveCall::Operation] the RPC operation for the page. # @param format_resource [Proc] A Proc object to format the resource object. The Proc should accept response as an # argument, and return a formatted resource object. Optional. # def initialize response, resource_field, operation, format_resource: nil @response = response @resource_field = resource_field @operation = operation @format_resource = format_resource end ## # Iterate over the resources. # # @yield [Object] Gives the resource objects in the page. # def each return enum_for :each unless block_given? return if @response.nil? # We trust that the field exists and is an Enumerable @response[@resource_field].each do |resource| resource = @format_resource.call resource if @format_resource yield resource end end ## # The page token to be used for the next RPC call. # # @return [String] # def next_page_token return if @response.nil? @response.next_page_token end ## # Truthiness of next_page_token. # # @return [Boolean] # def next_page_token? return if @response.nil? # rubocop:disable Style/ReturnNilInPredicateMethodDefinition !@response.next_page_token.empty? end end end end gapic-common-1.2.0/lib/gapic-common.rb0000644000004100000410000000112715143460047017564 0ustar www-datawww-data# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "gapic/common" gapic-common-1.2.0/RELEASING.md0000644000004100000410000000563515143460047015763 0ustar www-datawww-data# Releasing gapic-common The Google Ruby GAX project uses [semantic versioning](http://semver.org). Replace the `` and `` placeholders shown in the examples below with the appropriate numbers, e.g. `0.1.0` and `0.2.0`. After all [pull requests](https://github.com/googleapis/gax-ruby/pulls) for a release have been merged and all [Travis builds](https://travis-ci.org/googleapis/gax-ruby) are green, you may create a release as follows: 1. If you haven't already, switch to the master branch, ensure that you have no changes, and pull from origin. ```sh $ git checkout master $ git status $ git pull master --rebase ``` 1. Build the gem locally. (Depending on your environment, you may need to `bundle exec` to rake commands; this will be shown.) ```sh $ bundle exec rake build ``` 1. Install the gem locally. ```sh $ bundle exec rake install ``` 1. Using IRB (not `rake console`!), manually test the gem that you installed in the previous step. 1. Update the `CHANGELOG.md`. Write bullet-point lists of the major and minor changes. You can also add examples, fixes, thank yous, and anything else helpful or relevant. See google-cloud-node [v0.18.0](https://github.com/GoogleCloudPlatform/google-cloud-node/releases/tag/v0.18.0) for an example with all the bells and whistles. 1. Edit `lib/gapic/version.rb` file, changing the value of `VERSION` to your new version number. This repo requires a PR for all changes so doing this in a branch is best. 1. Run the tests, one last time. ```sh $ bundle update $ bundle exec rake spec ``` 1. Commit your changes. Copy and paste the significant points from your `CHANGELOG.md` edit as the description in your commit message. ```sh $ git commit -am "Release gapic-common ..." ``` 1. Tag the version after all changes have been merged. ```sh $ git tag gapic-common/v ``` 1. Push the tag. ```sh $ git push gapic-common/v ``` 1. Wait until the [Travis build](https://travis-ci.org/googleapis/gax-ruby) has passed for the tag. 1. Push the gem to [RubyGems.org](https://rubygems.org/gems/google-cloud). ```sh $ gem push gapic-common-.gem ``` 1. On the [gax-ruby releases page](https://github.com/googleapis/gax-ruby/releases), click [Draft a new release](https://github.com/googleapis/gax-ruby/releases/new). Complete the form. Include the bullet-point lists of the major and minor changes from the gem's `CHANGELOG.md`. You can also add examples, fixes, thank yous, and anything else helpful or relevant. 1. Click `Publish release`. 1. Wait until the last tag build job has successfully completed on Travis. Then push your commits to the master branch. This will trigger another [Travis](https://travis-ci.org/googleapis/gax-ruby) build on master branch. ```sh $ git push master ``` High fives all around!gapic-common-1.2.0/.yardopts0000644000004100000410000000027415143460047015770 0ustar www-datawww-data--no-private --title=GAPIC common library --markup markdown --markup-provider redcarpet --main README.md ./lib/**/*.rb - CONTRIBUTING.md CHANGELOG.md CODE_OF_CONDUCT.md LICENSE README.md gapic-common-1.2.0/CODE_OF_CONDUCT.md0000644000004100000410000000367515143460047016731 0ustar www-datawww-data# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) gapic-common-1.2.0/LICENSE0000644000004100000410000000105015143460047015120 0ustar www-datawww-dataCopyright 2019 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. gapic-common-1.2.0/gapic-common.gemspec0000644000004100000410000000671115143460047020042 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: gapic-common 1.2.0 ruby lib Gem::Specification.new do |s| s.name = "gapic-common".freeze s.version = "1.2.0".freeze s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Google API Authors".freeze] s.date = "1980-01-02" s.email = ["googleapis-packages@google.com".freeze] s.files = [".yardopts".freeze, "CHANGELOG.md".freeze, "CODE_OF_CONDUCT.md".freeze, "CONTRIBUTING.md".freeze, "LICENSE".freeze, "README.md".freeze, "RELEASING.md".freeze, "lib/gapic-common.rb".freeze, "lib/gapic/call_options.rb".freeze, "lib/gapic/call_options/error_codes.rb".freeze, "lib/gapic/call_options/retry_policy.rb".freeze, "lib/gapic/common.rb".freeze, "lib/gapic/common/error.rb".freeze, "lib/gapic/common/error_codes.rb".freeze, "lib/gapic/common/polling_harness.rb".freeze, "lib/gapic/common/retry_policy.rb".freeze, "lib/gapic/common/version.rb".freeze, "lib/gapic/config.rb".freeze, "lib/gapic/config/method.rb".freeze, "lib/gapic/generic_lro/base_operation.rb".freeze, "lib/gapic/generic_lro/operation.rb".freeze, "lib/gapic/grpc.rb".freeze, "lib/gapic/grpc/errors.rb".freeze, "lib/gapic/grpc/service_stub.rb".freeze, "lib/gapic/grpc/service_stub/channel.rb".freeze, "lib/gapic/grpc/service_stub/channel_pool.rb".freeze, "lib/gapic/grpc/service_stub/rpc_call.rb".freeze, "lib/gapic/grpc/status_details.rb".freeze, "lib/gapic/headers.rb".freeze, "lib/gapic/logging_concerns.rb".freeze, "lib/gapic/lru_hash.rb".freeze, "lib/gapic/operation.rb".freeze, "lib/gapic/operation/retry_policy.rb".freeze, "lib/gapic/paged_enumerable.rb".freeze, "lib/gapic/protobuf.rb".freeze, "lib/gapic/rest.rb".freeze, "lib/gapic/rest/client_stub.rb".freeze, "lib/gapic/rest/error.rb".freeze, "lib/gapic/rest/faraday_middleware.rb".freeze, "lib/gapic/rest/grpc_transcoder.rb".freeze, "lib/gapic/rest/grpc_transcoder/http_binding.rb".freeze, "lib/gapic/rest/http_binding_override_configuration.rb".freeze, "lib/gapic/rest/operation.rb".freeze, "lib/gapic/rest/paged_enumerable.rb".freeze, "lib/gapic/rest/server_stream.rb".freeze, "lib/gapic/rest/threaded_enumerator.rb".freeze, "lib/gapic/rest/transport_operation.rb".freeze, "lib/gapic/stream_input.rb".freeze, "lib/gapic/universe_domain_concerns.rb".freeze] s.homepage = "https://github.com/googleapis/ruby-core-libraries".freeze s.licenses = ["Apache-2.0".freeze] s.required_ruby_version = Gem::Requirement.new(">= 3.1".freeze) s.rubygems_version = "3.6.9".freeze s.summary = "Common code for GAPIC-generated API clients".freeze s.specification_version = 4 s.add_runtime_dependency(%q.freeze, [">= 1.9".freeze, "< 3.a".freeze]) s.add_runtime_dependency(%q.freeze, [">= 1.0".freeze, "< 3.a".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 2.2".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 0.1".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 4.26".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 1.6".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 1.15".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 1.12".freeze]) s.add_runtime_dependency(%q.freeze, ["~> 1.66".freeze]) end gapic-common-1.2.0/README.md0000644000004100000410000000273615143460047015406 0ustar www-datawww-dataGoogle API Extensions for Ruby ================================ Generated API Client common code (gapic-common) is a set of modules which aids the development of APIs for clients and servers based on [gRPC][] and Google API conventions. Application code will rarely need to use most of the classes within this library directly, but code generated automatically from the API definition files in [Google APIs][] can use services such as page streaming to provide a more convenient and idiomatic API surface to callers. [gRPC]: http://grpc.io [Google APIs]: https://github.com/googleapis/googleapis/ ## Supported Ruby Versions This library is supported on Ruby 3.0+. Google provides official support for Ruby versions that are actively supported by Ruby Core—that is, Ruby versions that are either in normal maintenance or in security maintenance, and not end of life. Older versions of Ruby _may_ still work, but are unsupported and not recommended. See https://www.ruby-lang.org/en/downloads/branches/ for details about the Ruby support schedule. ## Contributing Contributions to this library are always welcome and highly encouraged. See the {file:CONTRIBUTING.md CONTRIBUTING} documentation for more information on how to get started. ## Versioning This library is currently a **preview** with no guarantees of stability or support. Please get involved and let us know if you find it useful and we'll work towards a stable version. ## Disclaimer This is not an official Google product. gapic-common-1.2.0/CHANGELOG.md0000644000004100000410000001611415143460047015733 0ustar www-datawww-data# Release History ### 1.2.0 (2025-09-04) #### Features * update google-protobuf dependency ([#41](https://github.com/googleapis/ruby-core-libraries/issues/41)) ### 1.1.0 (2025-08-11) #### Features * add http binding configuration ([#38](https://github.com/googleapis/ruby-core-libraries/issues/38)) ### 1.0.1 (2025-07-17) #### Bug Fixes * Removed log preprocessing of large payload data when logging is disabled ([#35](https://github.com/googleapis/ruby-core-libraries/issues/35)) ### 1.0.0 (2025-04-30) #### Features * Bump version to 1.0 ([#33](https://github.com/googleapis/ruby-core-libraries/issues/33)) ### 0.26.0 (2025-04-30) #### Features * Updated required Ruby version to 3.1 ([#29](https://github.com/googleapis/ruby-core-libraries/issues/29)) ### 0.25.0 (2025-01-22) #### Features * Implement a polling harness ([#20](https://github.com/googleapis/ruby-core-libraries/issues/20)) ### 0.24.0 (2024-12-05) #### Features * Log requests and responses ([#1112](https://github.com/googleapis/gapic-generator-ruby/issues/1112)) #### Bug Fixes * Hardened deadline determination against Time.now hacking ([#942](https://github.com/googleapis/gapic-generator-ruby/issues/942)) ### 0.23.0 (2024-10-15) #### Features * Disable universe domain check if credentials include an explicit request to do so ([#1119](https://github.com/googleapis/gapic-generator-ruby/issues/1119)) ### 0.22.0 (2024-07-17) #### Features * Support for google-protobuf 4.x * Requires at least Ruby 3.0 ### 0.21.2 (2024-07-02) #### Bug Fixes * Start requiring ostruct in generated test helper files ([#1065](https://github.com/googleapis/gapic-generator-ruby/issues/1065)) ### 0.21.1 (2023-12-14) #### Bug Fixes * add missing module import for universe_domain_concerns ([#1016](https://github.com/googleapis/gapic-generator-ruby/issues/1016)) ### 0.21.0 (2023-12-13) #### Features * Drop support for Ruby 2.6 ([#1009](https://github.com/googleapis/gapic-generator-ruby/issues/1009)) * Honor universe domain in stubs ([#1008](https://github.com/googleapis/gapic-generator-ruby/issues/1008)) ### 0.20.0 (2023-08-31) #### Features * Add channel pooling for gapic clients ([#969](https://github.com/googleapis/gapic-generator-ruby/issues/969)) * Add LRU hash ([#970](https://github.com/googleapis/gapic-generator-ruby/issues/970)) #### Documentation * Minor fixes to YARD documentation links and parameters ([#959](https://github.com/googleapis/gapic-generator-ruby/issues/959)) ### 0.19.1 (2023-05-30) #### Bug Fixes * Fixed handling of optional fields in coerce ([#954](https://github.com/googleapis/gapic-generator-ruby/issues/954)) ### 0.19.0 (2023-05-26) #### Features * Compatibility with protobuf v23 generated map fields ([#948](https://github.com/googleapis/gapic-generator-ruby/issues/948)) ### 0.18.0 (2023-02-27) #### Features * add alias for details field in Rest Error ([#928](https://github.com/googleapis/gapic-generator-ruby/issues/928)) ### 0.17.1 (2023-02-09) #### Bug Fixes * add new class to the rest imports ([#913](https://github.com/googleapis/gapic-generator-ruby/issues/913)) ### 0.17.0 (2023-02-09) #### Features * add a transport operation class in Rest ([#911](https://github.com/googleapis/gapic-generator-ruby/issues/911)) ### 0.16.0 (2022-12-12) #### Features * custom regapic exception wrapping ([#866](https://github.com/googleapis/gapic-generator-ruby/issues/866)) ### 0.15.1 (2022-11-18) #### Bug Fixes * Fixed uninitialized constant when checking retry policy for a REST call ([#857](https://github.com/googleapis/gapic-generator-ruby/issues/857)) ### 0.15.0 (2022-11-17) #### Features * retry policy now works for REST calls ### 0.14.0 (2022-11-08) #### Features * add support for different types of credentials to REST #### Bug Fixes * deadlock fix ([#845](https://github.com/googleapis/gapic-generator-ruby/issues/845)) ### 0.13.0 (2022-10-26) #### Features * Implement server-side streaming support for REST calls in gapic-common ([#826](https://github.com/googleapis/gapic-generator-ruby/issues/826)) ### 0.12.0 (2022-09-15) #### Features * Support numeric_enums in the ClientStub ([#817](https://github.com/googleapis/gapic-generator-ruby/issues/817)) * parse details information from REST errors ([#815](https://github.com/googleapis/gapic-generator-ruby/issues/815)) * send protobuf version in headers ([#816](https://github.com/googleapis/gapic-generator-ruby/issues/816)) #### Bug Fixes * rewrap certain grpc errors ([#810](https://github.com/googleapis/gapic-generator-ruby/issues/810)) This will rewrap some GRPC::Unavailable errors that were caused by authentication failing as Gapic::GRPC::AuthorizationError which inherits from ::GRPC::Unauthenticated ### 0.11.1 (2022-08-03) #### Bug Fixes * error code of 0 is not an error, body template field can be nil ([#805](https://github.com/googleapis/gapic-generator-ruby/issues/805)) ### 0.11.0 (2022-07-27) #### Features * Add CallOptions#merge and CallOptions equality checking ([#802](https://github.com/googleapis/gapic-generator-ruby/issues/802)) #### Bug Fixes * transcoder should always preserve slashes ([#795](https://github.com/googleapis/gapic-generator-ruby/issues/795)) ### 0.10.0 (2022-06-20) #### Features * Require at least Ruby 2.6 * Support faraday 2.0 #### Bug Fixes * Fix precision issues in protobuf timestamp conversion * Fix some Ruby 3.0 keyword argument usage errors ### 0.9.0 (2022-05-18) #### Features * add full grpc transcoding to gapic-common #### Bug Fixes * small fixes for combined libraries and testing ### 0.8.0 / 2022-01-20 * Add generic LROs helpers. These are used for the Nonstandard (not conforming to AIP-151) Cloud LROs. ### 0.7.0 / 2021-08-03 * Require googleauth 0.17 for proper support of JWT credentials with custom scopes ### 0.6.0 / 2021-07-22 * Added helper for REST pagination ### 0.5.0 / 2021-06-15 * Provide a way to create `x-goog-api-client` headers with rest library version and/or without grpc library version ### 0.4.3 / 2021-06-10 * Fix file permissions. ### 0.4.2 / 2021-06-07 * Expand googleauth dependency to include 1.x * Add a REST PUT method helper to Gapic::Rest. ### 0.4.1 / 2021-04-15 * Provide a default value for the 'body' in the REST POST method in Gapic::Rest. ### 0.4.0 / 2021-02-23 * Support for the REST calls via the Gapic::Rest::ClientStub and other classes in Gapic::Rest REST support is still being developed. Notably the full retries handling is not implemented yet. ### 0.3.4 / 2020-08-07 * Support the :this_channel_is_insecure gRPC pseudo-credential, used by tests and emulators. ### 0.3.3 / 2020-08-05 * Retry configs properly handle error name strings. ### 0.3.2 / 2020-07-30 * Alias PagedEnumerable#next_page to PagedEnumerable#next_page! ### 0.3.1 / 2020-06-19 * Fix file permissions ### 0.3.0 / 2020-06-18 * Update the dependency on google-protobuf to 3.12.2 ### 0.2.1 / 2020-06-02 * Fix a crash when resetting a config field to nil when it has a parent but no default ### 0.2.0 / 2020-03-17 * Support default call options in Gapic::Operation * Fix implicit kwarg warnings under Ruby 2.7 ### 0.1.0 / 2020-01-09 Initial release