grpc 1.64.0.pre1 → 1.64.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Makefile +1 -1
- data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +8 -1
- data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +36 -27
- data/src/core/ext/transport/chttp2/transport/hpack_parser.h +2 -0
- data/src/core/ext/transport/chttp2/transport/internal.h +5 -7
- data/src/core/ext/transport/inproc/inproc_transport.cc +10 -18
- data/src/core/lib/promise/detail/promise_like.h +7 -1
- data/src/core/lib/surface/call.cc +1 -2
- data/src/core/lib/surface/legacy_channel.cc +6 -6
- data/src/core/lib/transport/transport.h +1 -1
- data/src/core/xds/xds_client/xds_client_stats.cc +14 -12
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 216c15088bec64bf4e1a578055e66a40e888d1873e55085a68901f39d7b81ee8
|
4
|
+
data.tar.gz: 2beb4d51c1730075fe13e4110eab0c77efd9a8fdd7e7595a520a534260ddbbcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eea200a7f5fce5930abc871cb6794cbe03403446c0b454fc3d333fd20e5644fd81db441ca452350814c0fd0dad665350025433a8e4449160b01fd7db2ffa74e5
|
7
|
+
data.tar.gz: 3b92cdb984f0e133f87966c3ad5deb2a417f0c65706774e758508e84ced457e812477c4756e1aeffcc29fdfd3d000da9f7fbd87bafb6449e204bbd95d7e9d070
|
data/Makefile
CHANGED
@@ -143,6 +143,8 @@ static bool g_default_server_keepalive_permit_without_calls = false;
|
|
143
143
|
|
144
144
|
#define MAX_CLIENT_STREAM_ID 0x7fffffffu
|
145
145
|
grpc_core::TraceFlag grpc_keepalive_trace(false, "http_keepalive");
|
146
|
+
grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount(false,
|
147
|
+
"chttp2_refcount");
|
146
148
|
|
147
149
|
// forward declarations of various callbacks that we'll build closures around
|
148
150
|
static void write_action_begin_locked(
|
@@ -593,7 +595,12 @@ static void init_keepalive_pings_if_enabled_locked(
|
|
593
595
|
grpc_chttp2_transport::grpc_chttp2_transport(
|
594
596
|
const grpc_core::ChannelArgs& channel_args, grpc_endpoint* ep,
|
595
597
|
bool is_client)
|
596
|
-
:
|
598
|
+
: grpc_core::RefCounted<grpc_chttp2_transport,
|
599
|
+
grpc_core::NonPolymorphicRefCount>(
|
600
|
+
GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_refcount)
|
601
|
+
? "chttp2_refcount"
|
602
|
+
: nullptr),
|
603
|
+
ep(ep),
|
597
604
|
peer_string(
|
598
605
|
grpc_core::Slice::FromCopiedString(grpc_endpoint_get_peer(ep))),
|
599
606
|
memory_owner(channel_args.GetObject<grpc_core::ResourceQuota>()
|
@@ -92,12 +92,14 @@ constexpr Base64InverseTable kBase64InverseTable;
|
|
92
92
|
class HPackParser::Input {
|
93
93
|
public:
|
94
94
|
Input(grpc_slice_refcount* current_slice_refcount, const uint8_t* begin,
|
95
|
-
const uint8_t* end, absl::BitGenRef bitsrc,
|
95
|
+
const uint8_t* end, absl::BitGenRef bitsrc,
|
96
|
+
HpackParseResult& frame_error, HpackParseResult& field_error)
|
96
97
|
: current_slice_refcount_(current_slice_refcount),
|
97
98
|
begin_(begin),
|
98
99
|
end_(end),
|
99
100
|
frontier_(begin),
|
100
|
-
|
101
|
+
frame_error_(frame_error),
|
102
|
+
field_error_(field_error),
|
101
103
|
bitsrc_(bitsrc) {}
|
102
104
|
|
103
105
|
// If input is backed by a slice, retrieve its refcount. If not, return
|
@@ -216,14 +218,18 @@ class HPackParser::Input {
|
|
216
218
|
|
217
219
|
// Check if we saw an EOF
|
218
220
|
bool eof_error() const {
|
219
|
-
return min_progress_size_ != 0 ||
|
221
|
+
return min_progress_size_ != 0 || frame_error_.connection_error();
|
222
|
+
}
|
223
|
+
|
224
|
+
// Reset the field error to be ok
|
225
|
+
void ClearFieldError() {
|
226
|
+
if (field_error_.ok()) return;
|
227
|
+
field_error_ = HpackParseResult();
|
220
228
|
}
|
221
229
|
|
222
230
|
// Minimum number of bytes to unstuck the current parse
|
223
231
|
size_t min_progress_size() const { return min_progress_size_; }
|
224
232
|
|
225
|
-
bool has_error() const { return !error_.ok(); }
|
226
|
-
|
227
233
|
// Set the current error - tweaks the error to include a stream id so that
|
228
234
|
// chttp2 does not close the connection.
|
229
235
|
// Intended for errors that are specific to a stream and recoverable.
|
@@ -247,10 +253,7 @@ class HPackParser::Input {
|
|
247
253
|
// read prior to being able to get further in this parse.
|
248
254
|
void UnexpectedEOF(size_t min_progress_size) {
|
249
255
|
CHECK_GT(min_progress_size, 0u);
|
250
|
-
if (
|
251
|
-
DCHECK(eof_error());
|
252
|
-
return;
|
253
|
-
}
|
256
|
+
if (eof_error()) return;
|
254
257
|
// Set min progress size, taking into account bytes parsed already but not
|
255
258
|
// consumed.
|
256
259
|
min_progress_size_ = min_progress_size + (begin_ - frontier_);
|
@@ -303,13 +306,18 @@ class HPackParser::Input {
|
|
303
306
|
// Do not use this directly, instead use SetErrorAndContinueParsing or
|
304
307
|
// SetErrorAndStopParsing.
|
305
308
|
void SetError(HpackParseResult error) {
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
+
SetErrorFor(frame_error_, error);
|
310
|
+
SetErrorFor(field_error_, std::move(error));
|
311
|
+
}
|
312
|
+
|
313
|
+
void SetErrorFor(HpackParseResult& error, HpackParseResult new_error) {
|
314
|
+
if (!error.ok() || min_progress_size_ > 0) {
|
315
|
+
if (new_error.connection_error() && !error.connection_error()) {
|
316
|
+
error = std::move(new_error); // connection errors dominate
|
309
317
|
}
|
310
318
|
return;
|
311
319
|
}
|
312
|
-
|
320
|
+
error = std::move(new_error);
|
313
321
|
}
|
314
322
|
|
315
323
|
// Refcount if we are backed by a slice
|
@@ -321,7 +329,8 @@ class HPackParser::Input {
|
|
321
329
|
// Frontier denotes the first byte past successfully processed input
|
322
330
|
const uint8_t* frontier_;
|
323
331
|
// Current error
|
324
|
-
HpackParseResult&
|
332
|
+
HpackParseResult& frame_error_;
|
333
|
+
HpackParseResult& field_error_;
|
325
334
|
// If the error was EOF, we flag it here by noting how many more bytes would
|
326
335
|
// be needed to make progress
|
327
336
|
size_t min_progress_size_ = 0;
|
@@ -598,6 +607,7 @@ class HPackParser::Parser {
|
|
598
607
|
bool ParseTop() {
|
599
608
|
DCHECK(state_.parse_state == ParseState::kTop);
|
600
609
|
auto cur = *input_->Next();
|
610
|
+
input_->ClearFieldError();
|
601
611
|
switch (cur >> 4) {
|
602
612
|
// Literal header not indexed - First byte format: 0000xxxx
|
603
613
|
// Literal header never indexed - First byte format: 0001xxxx
|
@@ -703,7 +713,7 @@ class HPackParser::Parser {
|
|
703
713
|
break;
|
704
714
|
}
|
705
715
|
gpr_log(
|
706
|
-
|
716
|
+
GPR_INFO, "HTTP:%d:%s:%s: %s%s", log_info_.stream_id, type,
|
707
717
|
log_info_.is_client ? "CLI" : "SVR", memento.md.DebugString().c_str(),
|
708
718
|
memento.parse_status == nullptr
|
709
719
|
? ""
|
@@ -952,11 +962,10 @@ class HPackParser::Parser {
|
|
952
962
|
state_.string_length)
|
953
963
|
: String::Parse(input_, state_.is_string_huff_compressed,
|
954
964
|
state_.string_length);
|
955
|
-
HpackParseResult& status = state_.frame_error;
|
956
965
|
absl::string_view key_string;
|
957
966
|
if (auto* s = absl::get_if<Slice>(&state_.key)) {
|
958
967
|
key_string = s->as_string_view();
|
959
|
-
if (
|
968
|
+
if (state_.field_error.ok()) {
|
960
969
|
auto r = ValidateKey(key_string);
|
961
970
|
if (r != ValidateMetadataResult::kOk) {
|
962
971
|
input_->SetErrorAndContinueParsing(
|
@@ -966,7 +975,7 @@ class HPackParser::Parser {
|
|
966
975
|
} else {
|
967
976
|
const auto* memento = absl::get<const HPackTable::Memento*>(state_.key);
|
968
977
|
key_string = memento->md.key();
|
969
|
-
if (
|
978
|
+
if (state_.field_error.ok() && memento->parse_status != nullptr) {
|
970
979
|
input_->SetErrorAndContinueParsing(*memento->parse_status);
|
971
980
|
}
|
972
981
|
}
|
@@ -993,16 +1002,16 @@ class HPackParser::Parser {
|
|
993
1002
|
key_string.size() + value.wire_size + hpack_constants::kEntryOverhead;
|
994
1003
|
auto md = grpc_metadata_batch::Parse(
|
995
1004
|
key_string, std::move(value_slice), state_.add_to_table, transport_size,
|
996
|
-
[key_string,
|
997
|
-
if (!
|
1005
|
+
[key_string, this](absl::string_view message, const Slice&) {
|
1006
|
+
if (!state_.field_error.ok()) return;
|
998
1007
|
input_->SetErrorAndContinueParsing(
|
999
1008
|
HpackParseResult::MetadataParseError(key_string));
|
1000
1009
|
gpr_log(GPR_ERROR, "Error parsing '%s' metadata: %s",
|
1001
1010
|
std::string(key_string).c_str(),
|
1002
1011
|
std::string(message).c_str());
|
1003
1012
|
});
|
1004
|
-
HPackTable::Memento memento{
|
1005
|
-
|
1013
|
+
HPackTable::Memento memento{
|
1014
|
+
std::move(md), state_.field_error.PersistentStreamErrorOrNullptr()};
|
1006
1015
|
input_->UpdateFrontier();
|
1007
1016
|
state_.parse_state = ParseState::kTop;
|
1008
1017
|
if (state_.add_to_table) {
|
@@ -1115,13 +1124,13 @@ grpc_error_handle HPackParser::Parse(
|
|
1115
1124
|
std::vector<uint8_t> buffer = std::move(unparsed_bytes_);
|
1116
1125
|
return ParseInput(
|
1117
1126
|
Input(nullptr, buffer.data(), buffer.data() + buffer.size(), bitsrc,
|
1118
|
-
state_.frame_error),
|
1127
|
+
state_.frame_error, state_.field_error),
|
1119
1128
|
is_last, call_tracer);
|
1120
1129
|
}
|
1121
|
-
return ParseInput(
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1130
|
+
return ParseInput(Input(slice.refcount, GRPC_SLICE_START_PTR(slice),
|
1131
|
+
GRPC_SLICE_END_PTR(slice), bitsrc, state_.frame_error,
|
1132
|
+
state_.field_error),
|
1133
|
+
is_last, call_tracer);
|
1125
1134
|
}
|
1126
1135
|
|
1127
1136
|
grpc_error_handle HPackParser::ParseInput(
|
@@ -235,6 +235,8 @@ class HPackParser {
|
|
235
235
|
HPackTable hpack_table;
|
236
236
|
// Error so far for this frame (set by class Input)
|
237
237
|
HpackParseResult frame_error;
|
238
|
+
// Error so far for this field (set by class Input)
|
239
|
+
HpackParseResult field_error;
|
238
240
|
// Length of frame so far.
|
239
241
|
uint32_t frame_length = 0;
|
240
242
|
// Length of the string being parsed
|
@@ -223,19 +223,17 @@ typedef enum {
|
|
223
223
|
GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED,
|
224
224
|
} grpc_chttp2_keepalive_state;
|
225
225
|
|
226
|
-
struct grpc_chttp2_transport final
|
227
|
-
|
226
|
+
struct grpc_chttp2_transport final
|
227
|
+
: public grpc_core::FilterStackTransport,
|
228
|
+
public grpc_core::RefCounted<grpc_chttp2_transport,
|
229
|
+
grpc_core::NonPolymorphicRefCount>,
|
230
|
+
public grpc_core::KeepsGrpcInitialized {
|
228
231
|
grpc_chttp2_transport(const grpc_core::ChannelArgs& channel_args,
|
229
232
|
grpc_endpoint* ep, bool is_client);
|
230
233
|
~grpc_chttp2_transport() override;
|
231
234
|
|
232
235
|
void Orphan() override;
|
233
236
|
|
234
|
-
grpc_core::RefCountedPtr<grpc_chttp2_transport> Ref() {
|
235
|
-
return grpc_core::FilterStackTransport::RefAsSubclass<
|
236
|
-
grpc_chttp2_transport>();
|
237
|
-
}
|
238
|
-
|
239
237
|
size_t SizeOfStream() const override;
|
240
238
|
bool HackyDisableStreamOpBatchCoalescingInConnectedChannel() const override;
|
241
239
|
void PerformStreamOp(grpc_stream* gs,
|
@@ -35,9 +35,8 @@
|
|
35
35
|
namespace grpc_core {
|
36
36
|
|
37
37
|
namespace {
|
38
|
-
class
|
39
|
-
|
40
|
-
class InprocServerTransport final : public ServerTransport {
|
38
|
+
class InprocServerTransport final : public RefCounted<InprocServerTransport>,
|
39
|
+
public ServerTransport {
|
41
40
|
public:
|
42
41
|
void SetAcceptor(Acceptor* acceptor) override {
|
43
42
|
acceptor_ = acceptor;
|
@@ -98,8 +97,6 @@ class InprocServerTransport final : public ServerTransport {
|
|
98
97
|
return acceptor_->CreateCall(std::move(md), acceptor_->CreateArena());
|
99
98
|
}
|
100
99
|
|
101
|
-
OrphanablePtr<InprocClientTransport> MakeClientTransport();
|
102
|
-
|
103
100
|
private:
|
104
101
|
enum class ConnectionState : uint8_t { kInitial, kReady, kDisconnected };
|
105
102
|
|
@@ -114,10 +111,6 @@ class InprocServerTransport final : public ServerTransport {
|
|
114
111
|
|
115
112
|
class InprocClientTransport final : public ClientTransport {
|
116
113
|
public:
|
117
|
-
explicit InprocClientTransport(
|
118
|
-
RefCountedPtr<InprocServerTransport> server_transport)
|
119
|
-
: server_transport_(std::move(server_transport)) {}
|
120
|
-
|
121
114
|
void StartCall(CallHandler call_handler) override {
|
122
115
|
call_handler.SpawnGuarded(
|
123
116
|
"pull_initial_metadata",
|
@@ -134,6 +127,10 @@ class InprocClientTransport final : public ClientTransport {
|
|
134
127
|
|
135
128
|
void Orphan() override { delete this; }
|
136
129
|
|
130
|
+
OrphanablePtr<Transport> GetServerTransport() {
|
131
|
+
return OrphanablePtr<Transport>(server_transport_->Ref().release());
|
132
|
+
}
|
133
|
+
|
137
134
|
FilterStackTransport* filter_stack_transport() override { return nullptr; }
|
138
135
|
ClientTransport* client_transport() override { return this; }
|
139
136
|
ServerTransport* server_transport() override { return nullptr; }
|
@@ -149,7 +146,8 @@ class InprocClientTransport final : public ClientTransport {
|
|
149
146
|
absl::UnavailableError("Client transport closed"));
|
150
147
|
}
|
151
148
|
|
152
|
-
|
149
|
+
RefCountedPtr<InprocServerTransport> server_transport_ =
|
150
|
+
MakeRefCounted<InprocServerTransport>();
|
153
151
|
};
|
154
152
|
|
155
153
|
bool UsePromiseBasedTransport() {
|
@@ -159,12 +157,6 @@ bool UsePromiseBasedTransport() {
|
|
159
157
|
return true;
|
160
158
|
}
|
161
159
|
|
162
|
-
OrphanablePtr<InprocClientTransport>
|
163
|
-
InprocServerTransport::MakeClientTransport() {
|
164
|
-
return MakeOrphanable<InprocClientTransport>(
|
165
|
-
RefAsSubclass<InprocServerTransport>());
|
166
|
-
}
|
167
|
-
|
168
160
|
OrphanablePtr<Channel> MakeLameChannel(absl::string_view why,
|
169
161
|
absl::Status error) {
|
170
162
|
gpr_log(GPR_ERROR, "%s: %s", std::string(why).c_str(),
|
@@ -206,8 +198,8 @@ OrphanablePtr<Channel> MakeInprocChannel(Server* server,
|
|
206
198
|
|
207
199
|
std::pair<OrphanablePtr<Transport>, OrphanablePtr<Transport>>
|
208
200
|
MakeInProcessTransportPair() {
|
209
|
-
auto
|
210
|
-
auto
|
201
|
+
auto client_transport = MakeOrphanable<InprocClientTransport>();
|
202
|
+
auto server_transport = client_transport->GetServerTransport();
|
211
203
|
return std::make_pair(std::move(client_transport),
|
212
204
|
std::move(server_transport));
|
213
205
|
}
|
@@ -71,7 +71,13 @@ class PromiseLike<void>;
|
|
71
71
|
|
72
72
|
template <typename F>
|
73
73
|
class PromiseLike<F, absl::enable_if_t<!std::is_void<
|
74
|
-
|
74
|
+
#if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \
|
75
|
+
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
76
|
+
std::invoke_result_t<F>
|
77
|
+
#else
|
78
|
+
typename std::result_of<F()>::type
|
79
|
+
#endif
|
80
|
+
>::value>> {
|
75
81
|
private:
|
76
82
|
GPR_NO_UNIQUE_ADDRESS F f_;
|
77
83
|
|
@@ -3732,8 +3732,7 @@ class MaybeOpImpl {
|
|
3732
3732
|
|
3733
3733
|
MaybeOpImpl(const MaybeOpImpl&) = delete;
|
3734
3734
|
MaybeOpImpl& operator=(const MaybeOpImpl&) = delete;
|
3735
|
-
MaybeOpImpl(MaybeOpImpl&& other) noexcept
|
3736
|
-
: state_(MoveState(other.state_)), op_(other.op_) {}
|
3735
|
+
MaybeOpImpl(MaybeOpImpl&& /*other*/) noexcept { Crash("not implemented"); }
|
3737
3736
|
MaybeOpImpl& operator=(MaybeOpImpl&& other) noexcept {
|
3738
3737
|
op_ = other.op_;
|
3739
3738
|
if (absl::holds_alternative<Dismissed>(state_)) {
|
@@ -93,13 +93,13 @@ absl::StatusOr<OrphanablePtr<Channel>> LegacyChannel::Create(
|
|
93
93
|
*(*r)->stats_plugin_group =
|
94
94
|
GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
95
95
|
} else {
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
.GetDefaultAuthority(target)));
|
96
|
+
std::string authority = args.GetOwnedString(GRPC_ARG_DEFAULT_AUTHORITY)
|
97
|
+
.value_or(CoreConfiguration::Get()
|
98
|
+
.resolver_registry()
|
99
|
+
.GetDefaultAuthority(target));
|
101
100
|
*(*r)->stats_plugin_group =
|
102
|
-
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
101
|
+
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
102
|
+
experimental::StatsPluginChannelScope(target, authority));
|
103
103
|
}
|
104
104
|
return MakeOrphanable<LegacyChannel>(
|
105
105
|
grpc_channel_stack_type_is_client(builder.channel_stack_type()),
|
@@ -502,7 +502,7 @@ class FilterStackTransport;
|
|
502
502
|
class ClientTransport;
|
503
503
|
class ServerTransport;
|
504
504
|
|
505
|
-
class Transport : public
|
505
|
+
class Transport : public Orphanable {
|
506
506
|
public:
|
507
507
|
struct RawPointerChannelArgTag {};
|
508
508
|
static absl::string_view ChannelArgName() { return GRPC_ARG_TRANSPORT; }
|
@@ -105,23 +105,25 @@ XdsClusterLocalityStats::XdsClusterLocalityStats(
|
|
105
105
|
eds_service_name_(eds_service_name),
|
106
106
|
name_(std::move(name)) {
|
107
107
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
108
|
-
gpr_log(
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
gpr_log(
|
109
|
+
GPR_INFO,
|
110
|
+
"[xds_client %p] created locality stats %p for {%s, %s, %s, %s}",
|
111
|
+
xds_client_.get(), this, std::string(lrs_server_).c_str(),
|
112
|
+
std::string(cluster_name_).c_str(),
|
113
|
+
std::string(eds_service_name_).c_str(),
|
114
|
+
name_ == nullptr ? "<none>" : name_->human_readable_string().c_str());
|
114
115
|
}
|
115
116
|
}
|
116
117
|
|
117
118
|
XdsClusterLocalityStats::~XdsClusterLocalityStats() {
|
118
119
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
119
|
-
gpr_log(
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
gpr_log(
|
121
|
+
GPR_INFO,
|
122
|
+
"[xds_client %p] destroying locality stats %p for {%s, %s, %s, %s}",
|
123
|
+
xds_client_.get(), this, std::string(lrs_server_).c_str(),
|
124
|
+
std::string(cluster_name_).c_str(),
|
125
|
+
std::string(eds_service_name_).c_str(),
|
126
|
+
name_ == nullptr ? "<none>" : name_->human_readable_string().c_str());
|
125
127
|
}
|
126
128
|
xds_client_->RemoveClusterLocalityStats(lrs_server_, cluster_name_,
|
127
129
|
eds_service_name_, name_, this);
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.64.
|
4
|
+
version: 1.64.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gRPC Authors
|
8
8
|
autorequire:
|
9
9
|
bindir: src/ruby/bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-protobuf
|
@@ -3571,7 +3571,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
3571
3571
|
- !ruby/object:Gem::Version
|
3572
3572
|
version: '0'
|
3573
3573
|
requirements: []
|
3574
|
-
rubygems_version: 3.5.
|
3574
|
+
rubygems_version: 3.5.17
|
3575
3575
|
signing_key:
|
3576
3576
|
specification_version: 4
|
3577
3577
|
summary: GRPC system in Ruby
|