connectrpc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +501 -0
- data/docs/design.md +504 -0
- data/docs/development.md +566 -0
- data/docs/grpc-web.md +165 -0
- data/docs/grpc.md +75 -0
- data/docs/rbs.md +469 -0
- data/docs/streaming.md +251 -0
- data/exe/protoc-gen-connectrpc-ruby +23 -0
- data/lib/connectrpc/bindings/descriptors/status.bin +15 -0
- data/lib/connectrpc/bindings/google_protobuf.rb +92 -0
- data/lib/connectrpc/cancellation.rb +220 -0
- data/lib/connectrpc/client.rb +260 -0
- data/lib/connectrpc/compression.rb +120 -0
- data/lib/connectrpc/deadline.rb +81 -0
- data/lib/connectrpc/error.rb +72 -0
- data/lib/connectrpc/generator/names.rb +105 -0
- data/lib/connectrpc/generator/rbs_renderer.rb +93 -0
- data/lib/connectrpc/generator/renderer.rb +115 -0
- data/lib/connectrpc/generator/runtime_names.rb +84 -0
- data/lib/connectrpc/generator/schema.rb +218 -0
- data/lib/connectrpc/generator/streaming_methods.rb +29 -0
- data/lib/connectrpc/generator.rb +42 -0
- data/lib/connectrpc/get_query.rb +159 -0
- data/lib/connectrpc/grpc.rb +200 -0
- data/lib/connectrpc/grpc_client.rb +23 -0
- data/lib/connectrpc/grpc_server.rb +158 -0
- data/lib/connectrpc/grpc_web.rb +131 -0
- data/lib/connectrpc/grpc_web_cors.rb +135 -0
- data/lib/connectrpc/grpc_web_io.rb +156 -0
- data/lib/connectrpc/grpc_web_server.rb +207 -0
- data/lib/connectrpc/instrumentation.rb +216 -0
- data/lib/connectrpc/message_io.rb +47 -0
- data/lib/connectrpc/metadata.rb +105 -0
- data/lib/connectrpc/method.rb +68 -0
- data/lib/connectrpc/protocol.rb +189 -0
- data/lib/connectrpc/server.rb +398 -0
- data/lib/connectrpc/streaming/client.rb +104 -0
- data/lib/connectrpc/streaming/client_execution.rb +87 -0
- data/lib/connectrpc/streaming/client_scope.rb +105 -0
- data/lib/connectrpc/streaming/framing.rb +123 -0
- data/lib/connectrpc/streaming/framing_io.rb +61 -0
- data/lib/connectrpc/streaming/method.rb +33 -0
- data/lib/connectrpc/streaming/server.rb +122 -0
- data/lib/connectrpc/streaming/server_execution.rb +88 -0
- data/lib/connectrpc/streaming/server_terminal.rb +70 -0
- data/lib/connectrpc/streaming/session.rb +143 -0
- data/lib/connectrpc/streaming/session_completion.rb +134 -0
- data/lib/connectrpc/streaming/session_io.rb +107 -0
- data/lib/connectrpc/streaming/session_messages.rb +119 -0
- data/lib/connectrpc/streaming/strategy.rb +95 -0
- data/lib/connectrpc/streaming/streams.rb +116 -0
- data/lib/connectrpc/streaming/terminal.rb +52 -0
- data/lib/connectrpc/transports/net_http.rb +246 -0
- data/lib/connectrpc/version.rb +5 -0
- data/lib/connectrpc.rb +38 -0
- data/rbs/google_protobuf_4_36/runtime.rbs +41 -0
- data/sig/connectrpc.rbs +772 -0
- data/sig/manifest.yaml +2 -0
- data/third_party/README.md +16 -0
- data/third_party/google/LICENSE +201 -0
- data/third_party/google/rpc/status.proto +48 -0
- data/third_party/protobuf-LICENSE +32 -0
- metadata +106 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ConnectRPC
|
|
4
|
+
class StreamStateError < StandardError; end
|
|
5
|
+
class StreamNotConsumedError < StreamStateError; end
|
|
6
|
+
|
|
7
|
+
StreamRequest = Struct.new(:url, :http_method, :headers, :deadline, :lifecycle, :cancellation, keyword_init: true)
|
|
8
|
+
StreamHead = Struct.new(:status, :headers, keyword_init: true)
|
|
9
|
+
|
|
10
|
+
class StreamingContext < Context
|
|
11
|
+
def initialize(publish:, request_metadata: {}, deadline: nil, lifecycle: nil, cancellation: nil)
|
|
12
|
+
super(request_metadata: request_metadata, deadline: deadline, lifecycle: lifecycle, cancellation: cancellation)
|
|
13
|
+
@publish = publish
|
|
14
|
+
@headers_sent = false
|
|
15
|
+
@owner_thread = Thread.current
|
|
16
|
+
@owner_scheduler = Fiber.scheduler
|
|
17
|
+
@stream_closed = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def send_headers(metadata: {})
|
|
21
|
+
check_headers_scope!
|
|
22
|
+
raise StreamStateError, "Response headers already published" if @headers_sent
|
|
23
|
+
|
|
24
|
+
check!
|
|
25
|
+
Metadata.new(metadata).each { |key, values| @response_metadata[key] = values }
|
|
26
|
+
@response_metadata.freeze
|
|
27
|
+
@headers_sent = true
|
|
28
|
+
@publish.call(@response_metadata)
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def close
|
|
33
|
+
@stream_closed = true
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def check_headers_scope!
|
|
40
|
+
raise StreamStateError, "Stream scope is closed" if @stream_closed
|
|
41
|
+
return if Thread.current.equal?(@owner_thread) && Fiber.scheduler.equal?(@owner_scheduler)
|
|
42
|
+
|
|
43
|
+
raise StreamStateError, "Use the stream's owning reactor and thread"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def publish_headers(check: true)
|
|
47
|
+
return if @headers_sent
|
|
48
|
+
return send_headers if check
|
|
49
|
+
|
|
50
|
+
@response_metadata.freeze
|
|
51
|
+
@headers_sent = true
|
|
52
|
+
@publish.call(@response_metadata)
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class ResponseReader
|
|
58
|
+
def initialize(session)
|
|
59
|
+
@session = session
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def receive = @session.receive
|
|
63
|
+
def headers = @session.headers
|
|
64
|
+
def trailers = @session.trailers
|
|
65
|
+
def abandon = @session.abandon
|
|
66
|
+
|
|
67
|
+
def each
|
|
68
|
+
raise ArgumentError, "A block is required" unless block_given?
|
|
69
|
+
|
|
70
|
+
while true # rubocop:disable Style/InfiniteLoop -- Kernel.loop swallows application StopIteration.
|
|
71
|
+
case message = receive
|
|
72
|
+
when nil then break
|
|
73
|
+
else yield message
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class RequestWriter
|
|
81
|
+
def initialize(session)
|
|
82
|
+
@session = session
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def send_message(message) = @session.send_message(message)
|
|
86
|
+
def close_send = @session.close_send
|
|
87
|
+
def abandon = @session.abandon
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class ClientDuplex < ResponseReader
|
|
91
|
+
def send_message(message) = @session.send_message(message)
|
|
92
|
+
def close_send = @session.close_send
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class RequestReader < ResponseReader; end
|
|
96
|
+
|
|
97
|
+
class ResponseWriter
|
|
98
|
+
def initialize(session, context)
|
|
99
|
+
@session = session
|
|
100
|
+
@context = context
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def send_message(message) = @session.send_message(message)
|
|
104
|
+
def send_headers(metadata: {}) = @context.send_headers(metadata: metadata)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class ServerDuplex < RequestReader
|
|
108
|
+
def initialize(session, context)
|
|
109
|
+
super(session)
|
|
110
|
+
@context = context
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def send_message(message) = @session.send_message(message)
|
|
114
|
+
def send_headers(metadata: {}) = @context.send_headers(metadata: metadata)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ConnectRPC
|
|
4
|
+
module Streaming
|
|
5
|
+
def self.parse_terminal(bytes, metadata: Metadata.new, on_error: nil)
|
|
6
|
+
object = JSON.parse(bytes, max_nesting: 64)
|
|
7
|
+
raise ArgumentError unless object.is_a?(Hash)
|
|
8
|
+
|
|
9
|
+
trailers = terminal_metadata(object)
|
|
10
|
+
[terminal_error(object["error"], metadata, trailers), trailers]
|
|
11
|
+
rescue JSON::ParserError, ArgumentError, TypeError, EncodingError => e
|
|
12
|
+
on_error&.call(e)
|
|
13
|
+
raise Error.new(:internal, "Malformed streaming terminal"), cause: nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.terminal_metadata(object)
|
|
17
|
+
empty = {} #: headers
|
|
18
|
+
trailers = object.fetch("metadata", empty)
|
|
19
|
+
raise ArgumentError unless trailers.is_a?(Hash)
|
|
20
|
+
|
|
21
|
+
Protocol.metadata(trailers).freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.terminal_error(error, metadata, trailers)
|
|
25
|
+
return if error.nil?
|
|
26
|
+
raise ArgumentError unless Protocol.valid_wire_error?(error)
|
|
27
|
+
|
|
28
|
+
empty = [] #: Array[ErrorDetail]
|
|
29
|
+
details = Protocol.wire_details(error.fetch("details", empty))
|
|
30
|
+
code = Error::HTTP_STATUS.key?(error["code"]) ? error["code"] : "unknown"
|
|
31
|
+
Error.new(code, error.fetch("message", ""), details: details, metadata: metadata, trailers: trailers)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.terminal_bytes(error, trailers, wire_limit:, limit:)
|
|
35
|
+
# @type var object: Hash[String, headers | Hash[String, String | Array[Hash[String, String]]]]
|
|
36
|
+
object = { "metadata" => trailers.to_h }
|
|
37
|
+
object["error"] = error.to_h if error
|
|
38
|
+
bytes = JSON.generate(object, max_nesting: 64)
|
|
39
|
+
return [bytes, error] if bytes.bytesize <= wire_limit && bytes.bytesize <= limit
|
|
40
|
+
|
|
41
|
+
minimal_terminal(wire_limit, limit)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.minimal_terminal(wire_limit, limit)
|
|
45
|
+
replacement = Error.new(:resource_exhausted, "Terminal exceeds byte limit")
|
|
46
|
+
bytes = JSON.generate({ "error" => { "code" => replacement.code } })
|
|
47
|
+
raise replacement if bytes.bytesize > wire_limit || bytes.bytesize > limit
|
|
48
|
+
|
|
49
|
+
[bytes, replacement]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "openssl"
|
|
5
|
+
require_relative "../../connectrpc"
|
|
6
|
+
|
|
7
|
+
module ConnectRPC
|
|
8
|
+
module Transports
|
|
9
|
+
class NetHTTP # rubocop:disable Metrics/ClassLength
|
|
10
|
+
# Net::HTTP uses the open timeout again for TLS. Recompute it from the
|
|
11
|
+
# original deadline after TCP/DNS, rather than starting another budget.
|
|
12
|
+
class Connection < Net::HTTP
|
|
13
|
+
attr_accessor :deadline, :cancellation, :socket_lifecycle
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def check_cancellation!
|
|
18
|
+
cancellation ? cancellation.check! : deadline&.check!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def connect
|
|
22
|
+
check_cancellation!
|
|
23
|
+
# begin_transport can reconnect a closed socket even with retries
|
|
24
|
+
# disabled. A second socket would escape the call's watchdog.
|
|
25
|
+
raise IOError, "Owned connection is closed" if @socket
|
|
26
|
+
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def begin_transport(request)
|
|
31
|
+
check_cancellation!
|
|
32
|
+
super
|
|
33
|
+
request["connect-timeout-ms"] = deadline.timeout_ms if deadline
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ssl_socket_connect(socket, _timeout)
|
|
37
|
+
socket_lifecycle&.attach(socket.to_io)
|
|
38
|
+
check_cancellation!
|
|
39
|
+
super(socket, deadline ? deadline.native_timeout : Deadline::MAX_NATIVE_WAIT)
|
|
40
|
+
check_cancellation!
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Owns only this call's raw socket. Closing wakes Net::HTTP's blocking
|
|
45
|
+
# read/write waits even when individual header/body reads keep progressing.
|
|
46
|
+
class Watchdog
|
|
47
|
+
def initialize(socket, deadline)
|
|
48
|
+
@mutex = Mutex.new
|
|
49
|
+
@condition = ConditionVariable.new
|
|
50
|
+
@done = false
|
|
51
|
+
@thread = Thread.new { watch(socket, deadline) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def watch(socket, deadline)
|
|
55
|
+
@mutex.synchronize do
|
|
56
|
+
@condition.wait(@mutex, deadline.native_timeout) until @done || deadline.expired?
|
|
57
|
+
close_socket(socket) unless @done
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def close_socket(socket)
|
|
62
|
+
socket.shutdown(Socket::SHUT_RDWR)
|
|
63
|
+
socket.close
|
|
64
|
+
rescue IOError, SystemCallError
|
|
65
|
+
# Net::HTTP may have closed the same owned socket first.
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def stop
|
|
70
|
+
@mutex.synchronize do
|
|
71
|
+
@done = true
|
|
72
|
+
@condition.signal
|
|
73
|
+
end
|
|
74
|
+
@thread.join
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Retirement and callback closure share this guard. Unregister alone
|
|
79
|
+
# cannot prevent an already-running callback from touching a reused FD.
|
|
80
|
+
class SocketLifecycle
|
|
81
|
+
def initialize(cancellation)
|
|
82
|
+
@mutex = Mutex.new
|
|
83
|
+
@socket = nil
|
|
84
|
+
@closed = false
|
|
85
|
+
@retired = false
|
|
86
|
+
@registration = cancellation&.on_cancel { close }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def attach(socket)
|
|
90
|
+
@mutex.synchronize do
|
|
91
|
+
return if @retired
|
|
92
|
+
|
|
93
|
+
@socket = socket
|
|
94
|
+
close_socket if @closed
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def close
|
|
99
|
+
@mutex.synchronize do
|
|
100
|
+
return if @retired
|
|
101
|
+
|
|
102
|
+
@closed = true
|
|
103
|
+
close_socket
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def retire
|
|
108
|
+
@mutex.synchronize do
|
|
109
|
+
@retired = true
|
|
110
|
+
@socket = nil
|
|
111
|
+
end
|
|
112
|
+
@registration&.unregister
|
|
113
|
+
@registration = nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
def close_socket
|
|
119
|
+
@socket&.shutdown(Socket::SHUT_RDWR)
|
|
120
|
+
@socket&.close
|
|
121
|
+
rescue IOError, SystemCallError
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def call(request)
|
|
127
|
+
CallCancellation.with_request(request) { |outgoing| perform_call(outgoing) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def perform_call(request) # rubocop:disable Metrics/MethodLength
|
|
133
|
+
deadline = request.deadline
|
|
134
|
+
outgoing = prepare_request(request)
|
|
135
|
+
http = connection(request.url, deadline)
|
|
136
|
+
http.cancellation = request.cancellation
|
|
137
|
+
with_connection(http, deadline, request.cancellation) { exchange(http, request, outgoing) }
|
|
138
|
+
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout,
|
|
139
|
+
SocketError, IOError, SystemCallError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
|
140
|
+
OpenSSL::SSL::SSLError => e
|
|
141
|
+
request.lifecycle&.record_failure(e)
|
|
142
|
+
check_request!(request)
|
|
143
|
+
raise Error.new(:unavailable, "HTTP transport failed"), cause: nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def check_request!(request)
|
|
147
|
+
request.cancellation ? request.cancellation.check! : request.deadline&.check!
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def prepare_request(request)
|
|
151
|
+
check_request!(request)
|
|
152
|
+
outgoing = outgoing_request(request)
|
|
153
|
+
check_request!(request)
|
|
154
|
+
outgoing
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Keep startup ownership and terminal retirement in one ensure.
|
|
158
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
159
|
+
def with_connection(http, deadline, cancellation = nil)
|
|
160
|
+
sockets = SocketLifecycle.new(cancellation)
|
|
161
|
+
http.socket_lifecycle = sockets
|
|
162
|
+
cancellation&.check!
|
|
163
|
+
http.start
|
|
164
|
+
sockets.attach(http.instance_variable_get(:@socket).io.to_io)
|
|
165
|
+
cancellation ? cancellation.check! : deadline&.check!
|
|
166
|
+
# Pinned Net::HTTP exposes its BufferedIO; one call owns this raw socket.
|
|
167
|
+
watchdog = Watchdog.new(http.instance_variable_get(:@socket).io.to_io, deadline) if deadline
|
|
168
|
+
yield
|
|
169
|
+
ensure
|
|
170
|
+
watchdog&.stop
|
|
171
|
+
sockets&.retire
|
|
172
|
+
http.finish if http.started?
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
176
|
+
|
|
177
|
+
def exchange(http, request, outgoing)
|
|
178
|
+
result = nil
|
|
179
|
+
http.request(outgoing) do |response|
|
|
180
|
+
check_request!(request)
|
|
181
|
+
check_response_size!(response, request.response_limit)
|
|
182
|
+
body = read_body(response, request)
|
|
183
|
+
result = TransportResponse.new(status: response.code.to_i, headers: response.to_hash, body: body)
|
|
184
|
+
end
|
|
185
|
+
check_request!(request)
|
|
186
|
+
result
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def check_response_size!(response, limit)
|
|
190
|
+
length = Protocol.content_length!(response.get_fields("content-length"), invalid_code: :internal)
|
|
191
|
+
raise Error.new(:resource_exhausted, "Response exceeds byte limit") if length && length > limit
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def outgoing_request(request) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
195
|
+
headers = request.headers.merge("connection" => ["close"])
|
|
196
|
+
accept = request.headers.fetch("accept-encoding", ["identity"]).join(", ")
|
|
197
|
+
has_body = request.http_method != "GET"
|
|
198
|
+
outgoing = Net::HTTPGenericRequest.new(request.http_method, has_body, true, request.url.request_uri,
|
|
199
|
+
"accept-encoding" => accept)
|
|
200
|
+
headers.each do |key, values|
|
|
201
|
+
next if key == "accept-encoding"
|
|
202
|
+
|
|
203
|
+
values.each { |value| outgoing.add_field(key, value) }
|
|
204
|
+
end
|
|
205
|
+
outgoing.body = request.body unless request.http_method == "GET"
|
|
206
|
+
outgoing
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def read_body(response, request)
|
|
210
|
+
body = +"".b
|
|
211
|
+
response.read_body do |chunk|
|
|
212
|
+
check_request!(request)
|
|
213
|
+
if body.bytesize + chunk.bytesize > request.response_limit
|
|
214
|
+
raise Error.new(:resource_exhausted, "Response exceeds byte limit")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
body << chunk
|
|
218
|
+
end
|
|
219
|
+
body
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def verify_tls!(http)
|
|
223
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
224
|
+
http.verify_hostname = true
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def connection(uri, deadline)
|
|
228
|
+
http = Connection.new(uri.hostname, uri.port, nil)
|
|
229
|
+
http.deadline = deadline
|
|
230
|
+
http.use_ssl = uri.scheme == "https"
|
|
231
|
+
configure_http(http, deadline)
|
|
232
|
+
http
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def configure_http(http, deadline)
|
|
236
|
+
verify_tls!(http) if http.use_ssl?
|
|
237
|
+
native_timeout = deadline ? deadline.native_timeout : Deadline::MAX_NATIVE_WAIT
|
|
238
|
+
http.open_timeout = native_timeout
|
|
239
|
+
http.read_timeout = native_timeout
|
|
240
|
+
http.write_timeout = native_timeout
|
|
241
|
+
http.max_retries = 0
|
|
242
|
+
http.ignore_eof = false
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
data/lib/connectrpc.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "connectrpc/version"
|
|
4
|
+
require_relative "connectrpc/method"
|
|
5
|
+
require_relative "connectrpc/streaming/method"
|
|
6
|
+
require_relative "connectrpc/metadata"
|
|
7
|
+
require_relative "connectrpc/error"
|
|
8
|
+
require_relative "connectrpc/cancellation"
|
|
9
|
+
require_relative "connectrpc/deadline"
|
|
10
|
+
require_relative "connectrpc/protocol"
|
|
11
|
+
require_relative "connectrpc/compression"
|
|
12
|
+
require_relative "connectrpc/instrumentation"
|
|
13
|
+
require_relative "connectrpc/get_query"
|
|
14
|
+
require_relative "connectrpc/grpc"
|
|
15
|
+
require_relative "connectrpc/client"
|
|
16
|
+
require_relative "connectrpc/message_io"
|
|
17
|
+
require_relative "connectrpc/server"
|
|
18
|
+
require_relative "connectrpc/streaming/framing"
|
|
19
|
+
require_relative "connectrpc/streaming/framing_io"
|
|
20
|
+
require_relative "connectrpc/streaming/terminal"
|
|
21
|
+
require_relative "connectrpc/streaming/strategy"
|
|
22
|
+
require_relative "connectrpc/streaming/streams"
|
|
23
|
+
require_relative "connectrpc/streaming/session"
|
|
24
|
+
require_relative "connectrpc/streaming/session_messages"
|
|
25
|
+
require_relative "connectrpc/streaming/session_io"
|
|
26
|
+
require_relative "connectrpc/streaming/session_completion"
|
|
27
|
+
require_relative "connectrpc/streaming/client"
|
|
28
|
+
require_relative "connectrpc/streaming/client_scope"
|
|
29
|
+
require_relative "connectrpc/streaming/client_execution"
|
|
30
|
+
require_relative "connectrpc/grpc_client"
|
|
31
|
+
require_relative "connectrpc/streaming/server"
|
|
32
|
+
require_relative "connectrpc/streaming/server_execution"
|
|
33
|
+
require_relative "connectrpc/streaming/server_terminal"
|
|
34
|
+
require_relative "connectrpc/grpc_server"
|
|
35
|
+
require_relative "connectrpc/grpc_web"
|
|
36
|
+
require_relative "connectrpc/grpc_web_io"
|
|
37
|
+
require_relative "connectrpc/grpc_web_cors"
|
|
38
|
+
require_relative "connectrpc/grpc_web_server"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# protoc 36.2 / google-protobuf 4.36.2 compatibility shapes only.
|
|
2
|
+
# Official message field signatures remain upstream-owned. No iteration API.
|
|
3
|
+
module Google
|
|
4
|
+
module Protobuf
|
|
5
|
+
class AbstractMessage
|
|
6
|
+
end
|
|
7
|
+
interface _MessageClass[T]
|
|
8
|
+
end
|
|
9
|
+
class RepeatedField[Read, Write]
|
|
10
|
+
def []: (Integer index) -> Read?
|
|
11
|
+
def []=: (Integer index, Write value) -> nil
|
|
12
|
+
def <<: (Write value) -> self
|
|
13
|
+
end
|
|
14
|
+
class Map[KeyRead, ValueRead, KeyWrite, ValueWrite]
|
|
15
|
+
def []: (KeyWrite key) -> ValueRead?
|
|
16
|
+
def []=: (KeyWrite key, ValueWrite value) -> ValueWrite
|
|
17
|
+
end
|
|
18
|
+
interface _EnumModule
|
|
19
|
+
def lookup: (Integer) -> Symbol?
|
|
20
|
+
def resolve: (Symbol) -> Integer?
|
|
21
|
+
end
|
|
22
|
+
interface _SpecificDescriptor[T]
|
|
23
|
+
def msgclass: () -> T
|
|
24
|
+
end
|
|
25
|
+
interface _SpecificEnumDescriptor[T]
|
|
26
|
+
def enummodule: () -> T
|
|
27
|
+
end
|
|
28
|
+
class Descriptor
|
|
29
|
+
def msgclass: () -> Class
|
|
30
|
+
end
|
|
31
|
+
class EnumDescriptor
|
|
32
|
+
def enummodule: () -> Module
|
|
33
|
+
end
|
|
34
|
+
class DescriptorPool
|
|
35
|
+
def self.generated_pool: () -> DescriptorPool
|
|
36
|
+
# Other names can resolve to file/service/extension descriptors. Keep
|
|
37
|
+
# those runtime shapes opaque; upstream literal overloads refine messages.
|
|
38
|
+
def lookup: (String name) -> Object?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|