protocol-grpc 0.6.0 → 0.7.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/design.md +5 -5
- data/lib/protocol/grpc/header/message.rb +64 -0
- data/lib/protocol/grpc/header/metadata.rb +22 -0
- data/lib/protocol/grpc/header/status.rb +85 -0
- data/lib/protocol/grpc/header.rb +3 -107
- data/lib/protocol/grpc/interface.rb +3 -1
- data/lib/protocol/grpc/methods.rb +1 -1
- data/lib/protocol/grpc/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +5 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ead258154cb8fe775c509d2b4aa05aadee904b18f052ff72163559c45ffdae0
|
|
4
|
+
data.tar.gz: 5af2daafbecc85fcd2fa722f9c8e02a262997e0a7fe1fdc0196fab7af80cf2aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e417c6adce8b055da14fd619381f3de243022ed2e9a27841cb2fab0c0c5232c57bbd559728cfcbf72e1ab61e49981f93d100cde21d3a4d194c0f17a89bc1087
|
|
7
|
+
data.tar.gz: 88290f4fb1f059056e0a545eaae4d90efcb4c7b01e69937ecfa17370392092edd66ce178ed1ebab68da3fbb90bfe879ff02ac6ea20f9768e377faa01c7445aa4
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/design.md
CHANGED
|
@@ -140,7 +140,7 @@ module Protocol
|
|
|
140
140
|
|
|
141
141
|
# Parse service and method from gRPC path
|
|
142
142
|
# @parameter path [String] e.g., "/my_service.Greeter/SayHello"
|
|
143
|
-
# @returns [
|
|
143
|
+
# @returns [Tuple(String, String)] of service and method.
|
|
144
144
|
def self.parse_path(path)
|
|
145
145
|
parts = path.split("/")
|
|
146
146
|
[parts[1], parts[2]]
|
|
@@ -287,7 +287,7 @@ module Protocol
|
|
|
287
287
|
|
|
288
288
|
# Extract gRPC status message from headers
|
|
289
289
|
# @parameter headers [Protocol::HTTP::Headers]
|
|
290
|
-
# @returns [String
|
|
290
|
+
# @returns [String | Nil] Status message
|
|
291
291
|
def self.extract_message(headers)
|
|
292
292
|
message = headers["grpc-message"]
|
|
293
293
|
message ? URI.decode_www_form_component(message) : nil
|
|
@@ -329,7 +329,7 @@ module Protocol
|
|
|
329
329
|
# @parameter body [Protocol::HTTP::Body::Readable] The underlying HTTP body
|
|
330
330
|
# @parameter message_class [Class, nil] Protobuf message class with .decode method
|
|
331
331
|
# If nil, returns raw binary data (useful for channel adapters)
|
|
332
|
-
# @parameter encoding [String
|
|
332
|
+
# @parameter encoding [String | Nil] Compression encoding (from grpc-encoding header)
|
|
333
333
|
def initialize(body, message_class: nil, encoding: nil)
|
|
334
334
|
super(body)
|
|
335
335
|
@message_class = message_class
|
|
@@ -408,7 +408,7 @@ module Protocol
|
|
|
408
408
|
# Writes length-prefixed gRPC messages
|
|
409
409
|
# This is the standard writable body for gRPC - all gRPC requests use message framing
|
|
410
410
|
class Writable < Protocol::HTTP::Body::Writable
|
|
411
|
-
# @parameter encoding [String
|
|
411
|
+
# @parameter encoding [String | Nil] Compression encoding (gzip, deflate, identity)
|
|
412
412
|
# @parameter level [Integer] Compression level if encoding is used
|
|
413
413
|
def initialize(encoding: nil, level: Zlib::DEFAULT_COMPRESSION, **options)
|
|
414
414
|
super(**options)
|
|
@@ -574,7 +574,7 @@ module Protocol
|
|
|
574
574
|
end
|
|
575
575
|
|
|
576
576
|
# Get peer information (client address)
|
|
577
|
-
# @returns [String
|
|
577
|
+
# @returns [String | Nil]
|
|
578
578
|
def peer
|
|
579
579
|
@request.peer&.to_s
|
|
580
580
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "uri"
|
|
7
|
+
|
|
8
|
+
module Protocol
|
|
9
|
+
module GRPC
|
|
10
|
+
module Header
|
|
11
|
+
# The `grpc-message` header represents the gRPC status message.
|
|
12
|
+
#
|
|
13
|
+
# The `grpc-message` header contains a human-readable error message, URL-encoded according to RFC 3986.
|
|
14
|
+
# This header is optional and typically only present when there's an error (non-zero status code).
|
|
15
|
+
# This header can appear both as an initial header (for trailers-only responses) and as a trailer.
|
|
16
|
+
class Message < String
|
|
17
|
+
# Parse a message from a header value.
|
|
18
|
+
#
|
|
19
|
+
# @parameter value [String] The header value to parse.
|
|
20
|
+
# @returns [Message] A new Message instance.
|
|
21
|
+
def self.parse(value)
|
|
22
|
+
new(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Initialize the message header with the given value.
|
|
26
|
+
#
|
|
27
|
+
# @parameter value [String] The message value (will be URL-encoded if not already encoded).
|
|
28
|
+
def initialize(value)
|
|
29
|
+
super(value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Decode the URL-encoded message.
|
|
33
|
+
#
|
|
34
|
+
# @returns [String] The decoded message.
|
|
35
|
+
def decode
|
|
36
|
+
::URI.decode_www_form_component(self)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Encode the message for use in headers.
|
|
40
|
+
#
|
|
41
|
+
# @parameter message [String] The message to encode.
|
|
42
|
+
# @returns [String] The URL-encoded message.
|
|
43
|
+
def self.encode(message)
|
|
44
|
+
URI.encode_www_form_component(message).gsub("+", "%20")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Merge another message value (takes the new value, as message should only appear once)
|
|
48
|
+
# @parameter value [String] The new message value
|
|
49
|
+
def <<(value)
|
|
50
|
+
replace(value.to_s)
|
|
51
|
+
|
|
52
|
+
return self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Whether this header is acceptable in HTTP trailers.
|
|
56
|
+
# The `grpc-message` header can appear in trailers as per the gRPC specification.
|
|
57
|
+
# @returns [Boolean] `true`, as grpc-message can appear in trailers.
|
|
58
|
+
def self.trailer?
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "protocol/http"
|
|
7
|
+
|
|
8
|
+
module Protocol
|
|
9
|
+
module GRPC
|
|
10
|
+
module Header
|
|
11
|
+
# Base class for custom gRPC metadata (allowed in trailers).
|
|
12
|
+
class Metadata < Protocol::HTTP::Header::Split
|
|
13
|
+
# Whether this header is acceptable in HTTP trailers.
|
|
14
|
+
# The `grpc-metadata` header can appear in trailers as per the gRPC specification.
|
|
15
|
+
# @returns [Boolean] `true`, as grpc-metadata can appear in trailers.
|
|
16
|
+
def self.trailer?
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
module Protocol
|
|
7
|
+
module GRPC
|
|
8
|
+
module Header
|
|
9
|
+
# The `grpc-status` header represents the gRPC status code.
|
|
10
|
+
#
|
|
11
|
+
# The `grpc-status` header contains a numeric status code (0-16) indicating the result of the RPC call.
|
|
12
|
+
# Status code 0 indicates success (OK), while other codes indicate various error conditions.
|
|
13
|
+
# This header can appear both as an initial header (for trailers-only responses) and as a trailer.
|
|
14
|
+
class Status
|
|
15
|
+
# Parse a status code from a header value.
|
|
16
|
+
#
|
|
17
|
+
# @parameter value [String] The header value to parse.
|
|
18
|
+
# @returns [Status] A new Status instance.
|
|
19
|
+
def self.parse(value)
|
|
20
|
+
new(value.to_i)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Initialize the status header with the given value.
|
|
24
|
+
#
|
|
25
|
+
# @parameter value [String | Integer] The status code as a string or integer.
|
|
26
|
+
def initialize(value)
|
|
27
|
+
@value = value.to_i
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Get the status code as an integer.
|
|
31
|
+
#
|
|
32
|
+
# @returns [Integer] The status code.
|
|
33
|
+
def to_i
|
|
34
|
+
@value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Serialize the status code to a string.
|
|
38
|
+
#
|
|
39
|
+
# @returns [String] The status code as a string.
|
|
40
|
+
def to_s
|
|
41
|
+
@value.to_s
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Check equality with another status or integer value.
|
|
45
|
+
#
|
|
46
|
+
# @parameter other [Status | Integer] The value to compare with.
|
|
47
|
+
# @returns [Boolean] if the status codes are equal.
|
|
48
|
+
def ==(other)
|
|
49
|
+
@value == other.to_i
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
alias eql? ==
|
|
53
|
+
|
|
54
|
+
# Generate hash for use in Hash/Set collections.
|
|
55
|
+
#
|
|
56
|
+
# @returns [Integer] The hash value based on the status code.
|
|
57
|
+
def hash
|
|
58
|
+
@value.hash
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Check if this status represents success (status code 0).
|
|
62
|
+
#
|
|
63
|
+
# @returns [Boolean] `true` if the status code is 0 (OK).
|
|
64
|
+
def ok?
|
|
65
|
+
@value == 0
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Merge another status value (takes the new value, as status should only appear once)
|
|
69
|
+
# @parameter value [String | Integer] The new status code
|
|
70
|
+
def <<(value)
|
|
71
|
+
@value = value.to_i
|
|
72
|
+
|
|
73
|
+
return self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Whether this header is acceptable in HTTP trailers.
|
|
77
|
+
# The `grpc-status` header can appear in trailers as per the gRPC specification.
|
|
78
|
+
# @returns [Boolean] `true`, as grpc-status can appear in trailers.
|
|
79
|
+
def self.trailer?
|
|
80
|
+
true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/protocol/grpc/header.rb
CHANGED
|
@@ -4,120 +4,16 @@
|
|
|
4
4
|
# Copyright, 2025, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "protocol/http"
|
|
7
|
-
require "uri"
|
|
8
7
|
|
|
9
8
|
require_relative "status"
|
|
9
|
+
require_relative "header/status"
|
|
10
|
+
require_relative "header/message"
|
|
11
|
+
require_relative "header/metadata"
|
|
10
12
|
|
|
11
13
|
module Protocol
|
|
12
14
|
module GRPC
|
|
13
15
|
# @namespace
|
|
14
16
|
module Header
|
|
15
|
-
# The `grpc-status` header represents the gRPC status code.
|
|
16
|
-
#
|
|
17
|
-
# The `grpc-status` header contains a numeric status code (0-16) indicating the result of the RPC call.
|
|
18
|
-
# Status code 0 indicates success (OK), while other codes indicate various error conditions.
|
|
19
|
-
# This header can appear both as an initial header (for trailers-only responses) and as a trailer.
|
|
20
|
-
class Status
|
|
21
|
-
# Initialize the status header with the given value.
|
|
22
|
-
#
|
|
23
|
-
# @parameter value [String, Integer, Array] The status code as a string, integer, or array (takes first element).
|
|
24
|
-
def initialize(value)
|
|
25
|
-
@value = normalize_value(value)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Get the status code as an integer.
|
|
29
|
-
#
|
|
30
|
-
# @returns [Integer] The status code.
|
|
31
|
-
def to_i
|
|
32
|
-
@value
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Serialize the status code to a string.
|
|
36
|
-
#
|
|
37
|
-
# @returns [String] The status code as a string.
|
|
38
|
-
def to_s
|
|
39
|
-
@value.to_s
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Merge another status value (takes the new value, as status should only appear once)
|
|
43
|
-
# @parameter value [String, Integer, Array] The new status code
|
|
44
|
-
def <<(value)
|
|
45
|
-
@value = normalize_value(value)
|
|
46
|
-
self
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
|
-
# Normalize a value to an integer status code.
|
|
52
|
-
# Handles arrays (from external clients), strings, and integers.
|
|
53
|
-
# @parameter value [String, Integer, Array] The raw value
|
|
54
|
-
# @returns [Integer] The normalized status code
|
|
55
|
-
def normalize_value(value)
|
|
56
|
-
# Handle Array case (may occur with external clients)
|
|
57
|
-
actual_value = value.is_a?(Array) ? value.flatten.compact.first : value
|
|
58
|
-
actual_value.to_i
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Whether this header is acceptable in HTTP trailers.
|
|
62
|
-
# The `grpc-status` header can appear in trailers as per the gRPC specification.
|
|
63
|
-
# @returns [Boolean] `true`, as grpc-status can appear in trailers.
|
|
64
|
-
def self.trailer?
|
|
65
|
-
true
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# The `grpc-message` header represents the gRPC status message.
|
|
70
|
-
#
|
|
71
|
-
# The `grpc-message` header contains a human-readable error message, URL-encoded according to RFC 3986.
|
|
72
|
-
# This header is optional and typically only present when there's an error (non-zero status code).
|
|
73
|
-
# This header can appear both as an initial header (for trailers-only responses) and as a trailer.
|
|
74
|
-
class Message < String
|
|
75
|
-
# Initialize the message header with the given value.
|
|
76
|
-
#
|
|
77
|
-
# @parameter value [String] The message value (will be URL-encoded if not already encoded).
|
|
78
|
-
def initialize(value)
|
|
79
|
-
super(value.to_s)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Decode the URL-encoded message.
|
|
83
|
-
#
|
|
84
|
-
# @returns [String] The decoded message.
|
|
85
|
-
def decode
|
|
86
|
-
URI.decode_www_form_component(self)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Encode the message for use in headers.
|
|
90
|
-
#
|
|
91
|
-
# @parameter message [String] The message to encode.
|
|
92
|
-
# @returns [String] The URL-encoded message.
|
|
93
|
-
def self.encode(message)
|
|
94
|
-
URI.encode_www_form_component(message).gsub("+", "%20")
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Merge another message value (takes the new value, as message should only appear once)
|
|
98
|
-
# @parameter value [String] The new message value
|
|
99
|
-
def <<(value)
|
|
100
|
-
replace(value.to_s)
|
|
101
|
-
self
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Whether this header is acceptable in HTTP trailers.
|
|
105
|
-
# The `grpc-message` header can appear in trailers as per the gRPC specification.
|
|
106
|
-
# @returns [Boolean] `true`, as grpc-message can appear in trailers.
|
|
107
|
-
def self.trailer?
|
|
108
|
-
true
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Base class for custom gRPC metadata (allowed in trailers).
|
|
113
|
-
class Metadata < Protocol::HTTP::Header::Split
|
|
114
|
-
# Whether this header is acceptable in HTTP trailers.
|
|
115
|
-
# The `grpc-metadata` header can appear in trailers as per the gRPC specification.
|
|
116
|
-
# @returns [Boolean] `true`, as grpc-metadata can appear in trailers.
|
|
117
|
-
def self.trailer?
|
|
118
|
-
true
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
17
|
end
|
|
122
18
|
|
|
123
19
|
# Custom header policy for gRPC.
|
|
@@ -10,6 +10,8 @@ module Protocol
|
|
|
10
10
|
# Wrapper class to mark a message type as streamed.
|
|
11
11
|
# Used with the stream() helper method in RPC definitions.
|
|
12
12
|
class Streaming
|
|
13
|
+
# Initialize a new Streaming wrapper.
|
|
14
|
+
# @parameter message_class [Class] The message class being wrapped
|
|
13
15
|
def initialize(message_class)
|
|
14
16
|
@message_class = message_class
|
|
15
17
|
end
|
|
@@ -148,7 +150,7 @@ module Protocol
|
|
|
148
150
|
attr :name
|
|
149
151
|
|
|
150
152
|
# Build gRPC path for a method.
|
|
151
|
-
# @parameter method_name [String
|
|
153
|
+
# @parameter method_name [String | Symbol] Method name in PascalCase (e.g., :SayHello)
|
|
152
154
|
# @returns [String] gRPC path with PascalCase method name
|
|
153
155
|
def path(method_name)
|
|
154
156
|
Methods.build_path(@name, method_name.to_s)
|
|
@@ -20,7 +20,7 @@ module Protocol
|
|
|
20
20
|
|
|
21
21
|
# Parse service and method from gRPC path.
|
|
22
22
|
# @parameter path [String] e.g., "/my_service.Greeter/SayHello"
|
|
23
|
-
# @returns [Array(String
|
|
23
|
+
# @returns [Array(String | String)] [service, method]
|
|
24
24
|
def self.parse_path(path)
|
|
25
25
|
parts = path.split("/")
|
|
26
26
|
[parts[1], parts[2]]
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: protocol-grpc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -109,6 +109,9 @@ files:
|
|
|
109
109
|
- lib/protocol/grpc/call.rb
|
|
110
110
|
- lib/protocol/grpc/error.rb
|
|
111
111
|
- lib/protocol/grpc/header.rb
|
|
112
|
+
- lib/protocol/grpc/header/message.rb
|
|
113
|
+
- lib/protocol/grpc/header/metadata.rb
|
|
114
|
+
- lib/protocol/grpc/header/status.rb
|
|
112
115
|
- lib/protocol/grpc/health_check.rb
|
|
113
116
|
- lib/protocol/grpc/interface.rb
|
|
114
117
|
- lib/protocol/grpc/metadata.rb
|
|
@@ -139,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
139
142
|
- !ruby/object:Gem::Version
|
|
140
143
|
version: '0'
|
|
141
144
|
requirements: []
|
|
142
|
-
rubygems_version:
|
|
145
|
+
rubygems_version: 4.0.3
|
|
143
146
|
specification_version: 4
|
|
144
147
|
summary: Protocol abstractions for gRPC, built on top of protocol-http.
|
|
145
148
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|