async-grpc-xds 0.3.0 → 0.4.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/context/getting-started.md +363 -0
- data/context/index.yaml +14 -0
- data/lib/async/grpc/xds/cluster.rb +5 -5
- data/lib/async/grpc/xds/cluster_discovery_service.rb +56 -0
- data/lib/async/grpc/xds/config_source.rb +46 -0
- data/lib/async/grpc/xds/control_plane.rb +3 -3
- data/lib/async/grpc/xds/discovery_service.rb +69 -0
- data/lib/async/grpc/xds/endpoint_discovery_service.rb +56 -0
- data/lib/async/grpc/xds/server.rb +8 -2
- data/lib/async/grpc/xds/service.rb +5 -103
- data/lib/async/grpc/xds/stream.rb +102 -0
- data/lib/async/grpc/xds/version.rb +1 -1
- data/lib/async/grpc/xds.rb +5 -0
- data/proto/readme.md +8 -24
- data/readme.md +9 -6
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +10 -14
- metadata.gz.sig +3 -1
- data/fixtures/async/grpc/test_interface.rb +0 -79
- data/fixtures/async/grpc/test_message.rb +0 -56
- data/xds/Dockerfile.backend +0 -24
- data/xds/Dockerfile.control-plane +0 -22
- data/xds/backend_server.rb +0 -68
- data/xds/docker-compose.yaml +0 -89
- data/xds/go.mod +0 -22
- data/xds/go.sum +0 -82
- data/xds/readme.md +0 -95
- data/xds/test/async/grpc/xds/client.rb +0 -294
- data/xds/test/async/grpc/xds/control_plane.rb +0 -93
- data/xds/test_server.go +0 -355
- data/xds/update_protos.sh +0 -123
|
@@ -16,16 +16,22 @@ module Async
|
|
|
16
16
|
class Server
|
|
17
17
|
# Initialize an xDS server.
|
|
18
18
|
# @parameter control_plane [ControlPlane] The control plane to serve.
|
|
19
|
+
# @parameter services [Array(Class)] The discovery service classes to register.
|
|
19
20
|
# @parameter options [Hash] Default options forwarded to `Async::HTTP::Server`.
|
|
20
|
-
def initialize(control_plane = ControlPlane.new, **options)
|
|
21
|
+
def initialize(control_plane = ControlPlane.new, services: [Service], **options)
|
|
21
22
|
@control_plane = control_plane
|
|
22
23
|
@dispatcher = Async::GRPC::Dispatcher.new
|
|
23
|
-
@
|
|
24
|
+
@services = services.map do |service|
|
|
25
|
+
service.new(@control_plane).tap do |instance|
|
|
26
|
+
@dispatcher.register(instance)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
24
29
|
@options = options
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
attr :control_plane
|
|
28
33
|
attr :dispatcher
|
|
34
|
+
attr :services
|
|
29
35
|
|
|
30
36
|
# Run the xDS server on an endpoint.
|
|
31
37
|
# @parameter endpoint [Async::HTTP::Endpoint] The endpoint to bind.
|
|
@@ -3,29 +3,21 @@
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
4
|
# Copyright, 2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require "async"
|
|
7
|
-
require "async/queue"
|
|
8
|
-
require "async/grpc/service"
|
|
9
|
-
require "protocol/grpc/error"
|
|
10
|
-
require "protocol/grpc/status"
|
|
11
|
-
require "set"
|
|
12
|
-
|
|
13
6
|
require "envoy/service/discovery/v3/aggregated_discovery_service"
|
|
14
7
|
|
|
15
|
-
require_relative "
|
|
8
|
+
require_relative "discovery_service"
|
|
16
9
|
|
|
17
10
|
module Async
|
|
18
11
|
module GRPC
|
|
19
12
|
module XDS
|
|
20
13
|
# Serves Envoy Aggregated Discovery Service requests from a {ControlPlane}.
|
|
21
|
-
class Service <
|
|
14
|
+
class Service < DiscoveryService
|
|
22
15
|
SERVICE_NAME = "envoy.service.discovery.v3.AggregatedDiscoveryService"
|
|
23
16
|
|
|
24
17
|
# Initialize an Aggregated Discovery Service.
|
|
25
18
|
# @parameter control_plane [ControlPlane] The control plane that provides resources.
|
|
26
19
|
def initialize(control_plane)
|
|
27
|
-
super(Envoy::Service::Discovery::V3::AggregatedDiscoveryService, SERVICE_NAME)
|
|
28
|
-
@control_plane = control_plane
|
|
20
|
+
super(Envoy::Service::Discovery::V3::AggregatedDiscoveryService, SERVICE_NAME, control_plane)
|
|
29
21
|
end
|
|
30
22
|
|
|
31
23
|
# Serve a state-of-the-world Aggregated Discovery Service stream.
|
|
@@ -34,25 +26,7 @@ module Async
|
|
|
34
26
|
# @parameter call [Object] The gRPC call context.
|
|
35
27
|
# @asynchronous
|
|
36
28
|
def stream_aggregated_resources(input, output, call)
|
|
37
|
-
|
|
38
|
-
@control_plane.register_stream(stream)
|
|
39
|
-
|
|
40
|
-
reader = Async do
|
|
41
|
-
input.each do |request|
|
|
42
|
-
stream.request(request)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
writer = Async do
|
|
47
|
-
stream.run
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
reader.wait
|
|
51
|
-
ensure
|
|
52
|
-
stream&.close
|
|
53
|
-
reader&.stop
|
|
54
|
-
writer&.stop
|
|
55
|
-
@control_plane.remove_stream(stream) if stream
|
|
29
|
+
stream_resources(input, output)
|
|
56
30
|
end
|
|
57
31
|
|
|
58
32
|
# Reject a delta Aggregated Discovery Service stream, which is not supported.
|
|
@@ -61,79 +35,7 @@ module Async
|
|
|
61
35
|
# @parameter call [Object] The gRPC call context.
|
|
62
36
|
# @raises [Protocol::GRPC::Error] Always raised because delta xDS is not implemented.
|
|
63
37
|
def delta_aggregated_resources(input, output, call)
|
|
64
|
-
|
|
65
|
-
Protocol::GRPC::Status::UNIMPLEMENTED,
|
|
66
|
-
"Delta xDS is not implemented."
|
|
67
|
-
)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Represents one ADS stream and its subscribed resources.
|
|
71
|
-
class Stream
|
|
72
|
-
# Initialize an ADS stream.
|
|
73
|
-
# @parameter control_plane [ControlPlane] The control plane that provides resources.
|
|
74
|
-
# @parameter output [Interface(:write)] The discovery response stream.
|
|
75
|
-
def initialize(control_plane, output)
|
|
76
|
-
@control_plane = control_plane
|
|
77
|
-
@output = output
|
|
78
|
-
@subscriptions = Hash.new{|hash, type_url| hash[type_url] = Set.new}
|
|
79
|
-
@versions = {}
|
|
80
|
-
@queue = Async::Queue.new
|
|
81
|
-
@closed = false
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Process a discovery request and update the stream's subscriptions.
|
|
85
|
-
# @parameter request [Envoy::Service::Discovery::V3::DiscoveryRequest] The discovery request.
|
|
86
|
-
def request(request)
|
|
87
|
-
return if request.type_url.nil? || request.type_url.empty?
|
|
88
|
-
|
|
89
|
-
if request.error_detail
|
|
90
|
-
Console.warn(self, "Received xDS NACK.", type_url: request.type_url, error_detail: request.error_detail)
|
|
91
|
-
return
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
if request.resource_names.any?
|
|
95
|
-
@subscriptions[request.type_url].merge(request.resource_names)
|
|
96
|
-
else
|
|
97
|
-
@subscriptions[request.type_url]
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
@queue << request.type_url
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Schedule a resource type for delivery after it changes.
|
|
104
|
-
# @parameter type_url [String] The changed xDS resource type URL.
|
|
105
|
-
def changed(type_url)
|
|
106
|
-
@queue << type_url unless @closed
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Deliver scheduled resource updates until the stream closes.
|
|
110
|
-
# @asynchronous
|
|
111
|
-
def run
|
|
112
|
-
until @closed
|
|
113
|
-
type_url = @queue.dequeue
|
|
114
|
-
flush(type_url)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Deliver the latest resource version for a subscribed type.
|
|
119
|
-
# @parameter type_url [String] The xDS resource type URL.
|
|
120
|
-
def flush(type_url)
|
|
121
|
-
names = @subscriptions[type_url]
|
|
122
|
-
return unless names
|
|
123
|
-
|
|
124
|
-
version = @control_plane.version(type_url)
|
|
125
|
-
return if @versions[type_url] == version
|
|
126
|
-
|
|
127
|
-
response = @control_plane.response(type_url, names)
|
|
128
|
-
@output.write(response)
|
|
129
|
-
@versions[type_url] = version
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Close the stream and stop waiting for changes.
|
|
133
|
-
def close
|
|
134
|
-
@closed = true
|
|
135
|
-
@queue.close
|
|
136
|
-
end
|
|
38
|
+
delta_resources
|
|
137
39
|
end
|
|
138
40
|
end
|
|
139
41
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "async/queue"
|
|
7
|
+
require "protocol/grpc/error"
|
|
8
|
+
require "protocol/grpc/status"
|
|
9
|
+
require "set"
|
|
10
|
+
|
|
11
|
+
module Async
|
|
12
|
+
module GRPC
|
|
13
|
+
module XDS
|
|
14
|
+
# Represents one discovery stream and its subscribed resources.
|
|
15
|
+
class Stream
|
|
16
|
+
# Initialize a discovery stream.
|
|
17
|
+
# @parameter control_plane [ControlPlane] The control plane that provides resources.
|
|
18
|
+
# @parameter output [Interface(:write)] The discovery response stream.
|
|
19
|
+
# @parameter resource_type [String | Nil] The fixed resource type, or `nil` for aggregated discovery.
|
|
20
|
+
def initialize(control_plane, output, resource_type: nil)
|
|
21
|
+
@control_plane = control_plane
|
|
22
|
+
@output = output
|
|
23
|
+
@resource_type = resource_type
|
|
24
|
+
@subscriptions = {}
|
|
25
|
+
@versions = {}
|
|
26
|
+
@queue = Async::Queue.new
|
|
27
|
+
@closed = false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Process a discovery request and update the stream's subscriptions.
|
|
31
|
+
# @parameter request [Envoy::Service::Discovery::V3::DiscoveryRequest] The discovery request.
|
|
32
|
+
def request(request)
|
|
33
|
+
type_url = request.type_url
|
|
34
|
+
|
|
35
|
+
if @resource_type
|
|
36
|
+
if type_url.nil? || type_url.empty?
|
|
37
|
+
type_url = @resource_type
|
|
38
|
+
elsif type_url != @resource_type
|
|
39
|
+
raise Protocol::GRPC::Error.new(
|
|
40
|
+
Protocol::GRPC::Status::INVALID_ARGUMENT,
|
|
41
|
+
"Expected resource type #{@resource_type.inspect}, but received #{type_url.inspect}."
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
elsif type_url.nil? || type_url.empty?
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if request.error_detail
|
|
49
|
+
Console.warn(self, "Received xDS NACK.", type_url: type_url, error_detail: request.error_detail)
|
|
50
|
+
return
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
names = Set.new(request.resource_names)
|
|
54
|
+
if @subscriptions[type_url] != names
|
|
55
|
+
@subscriptions[type_url] = names
|
|
56
|
+
@versions.delete(type_url)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@queue << type_url
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Schedule a resource type for delivery after it changes.
|
|
63
|
+
# @parameter type_url [String] The changed xDS resource type URL.
|
|
64
|
+
def changed(type_url)
|
|
65
|
+
return if @resource_type && type_url != @resource_type
|
|
66
|
+
return unless @subscriptions.key?(type_url)
|
|
67
|
+
|
|
68
|
+
@queue << type_url unless @closed
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Deliver scheduled resource updates until the stream closes.
|
|
72
|
+
# @asynchronous
|
|
73
|
+
def run
|
|
74
|
+
until @closed
|
|
75
|
+
type_url = @queue.dequeue
|
|
76
|
+
flush(type_url)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Deliver the latest resource version for a subscribed type.
|
|
81
|
+
# @parameter type_url [String] The xDS resource type URL.
|
|
82
|
+
def flush(type_url)
|
|
83
|
+
names = @subscriptions[type_url]
|
|
84
|
+
return unless names
|
|
85
|
+
|
|
86
|
+
version = @control_plane.version(type_url)
|
|
87
|
+
return if @versions[type_url] == version
|
|
88
|
+
|
|
89
|
+
response = @control_plane.response(type_url, names)
|
|
90
|
+
@output.write(response)
|
|
91
|
+
@versions[type_url] = version
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Close the stream and stop waiting for changes.
|
|
95
|
+
def close
|
|
96
|
+
@closed = true
|
|
97
|
+
@queue.close
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/async/grpc/xds.rb
CHANGED
|
@@ -13,12 +13,17 @@ require_relative "xds/health_checker"
|
|
|
13
13
|
require_relative "xds/load_balancer"
|
|
14
14
|
require_relative "xds/context"
|
|
15
15
|
require_relative "xds/client"
|
|
16
|
+
require_relative "xds/config_source"
|
|
16
17
|
require_relative "xds/cluster"
|
|
17
18
|
require_relative "xds/endpoint"
|
|
18
19
|
require_relative "xds/http_health_check"
|
|
19
20
|
require_relative "xds/client_side_weighted_round_robin"
|
|
20
21
|
require_relative "xds/control_plane"
|
|
22
|
+
require_relative "xds/stream"
|
|
23
|
+
require_relative "xds/discovery_service"
|
|
21
24
|
require_relative "xds/service"
|
|
25
|
+
require_relative "xds/cluster_discovery_service"
|
|
26
|
+
require_relative "xds/endpoint_discovery_service"
|
|
22
27
|
require_relative "xds/server"
|
|
23
28
|
|
|
24
29
|
module Async
|
data/proto/readme.md
CHANGED
|
@@ -25,45 +25,29 @@ These files come from [envoyproxy/data-plane-api](https://github.com/envoyproxy/
|
|
|
25
25
|
To update these files, run:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
|
|
28
|
+
bundle exec bake update_protos
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# Clone envoy data-plane-api
|
|
35
|
-
git clone --depth 1 https://github.com/envoyproxy/data-plane-api.git /tmp/envoy-api
|
|
36
|
-
|
|
37
|
-
# Copy needed files
|
|
38
|
-
cp -r /tmp/envoy-api/envoy proto/
|
|
39
|
-
cp -r /tmp/envoy-api/google proto/
|
|
40
|
-
|
|
41
|
-
# Cleanup
|
|
42
|
-
rm -rf /tmp/envoy-api
|
|
43
|
-
```
|
|
31
|
+
This fetches the pinned upstream revisions defined in `bake.rb`, updates the vendored definitions, and regenerates the checked-in Ruby classes.
|
|
44
32
|
|
|
45
33
|
## Generating Ruby Code
|
|
46
34
|
|
|
47
35
|
After updating proto files, generate Ruby classes:
|
|
48
36
|
|
|
49
37
|
```bash
|
|
50
|
-
bundle exec bake
|
|
38
|
+
bundle exec bake generate_protos
|
|
51
39
|
```
|
|
52
40
|
|
|
53
41
|
## Version
|
|
54
42
|
|
|
55
|
-
|
|
43
|
+
The source repositories and revisions are defined by `PROTOBUF_SOURCES` in `bake.rb`. They include:
|
|
44
|
+
|
|
56
45
|
- `envoyproxy/data-plane-api` - Envoy API definitions
|
|
57
46
|
- `protocolbuffers/protobuf` - Google protobuf well-known types
|
|
58
47
|
- `googleapis/api-common-protos` - Google RPC status
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
cd /tmp/envoy-api
|
|
64
|
-
git checkout v1.30.0 # Use specific Envoy version
|
|
65
|
-
# Then copy files
|
|
66
|
-
```
|
|
48
|
+
- `cncf/xds` - xDS API definitions
|
|
49
|
+
- `cncf/udpa` - UDPA annotations
|
|
50
|
+
- `envoyproxy/protoc-gen-validate` - Validation annotations
|
|
67
51
|
|
|
68
52
|
## Note on Dependencies
|
|
69
53
|
|
data/readme.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
xDS support for `async-grpc` clients.
|
|
4
4
|
|
|
5
|
-
This gem contains the experimental xDS implementation extracted from `async-grpc`, including Envoy xDS protobuf definitions,
|
|
5
|
+
This gem contains the experimental xDS implementation extracted from `async-grpc`, including Envoy xDS protobuf definitions, aggregated and resource-specific discovery, CDS/EDS resource handling, and client-side load balancing.
|
|
6
6
|
|
|
7
7
|
[](https://github.com/socketry/async-grpc-xds/actions?workflow=Test)
|
|
8
8
|
|
|
@@ -10,22 +10,25 @@ This gem contains the experimental xDS implementation extracted from `async-grpc
|
|
|
10
10
|
|
|
11
11
|
Please see the [project documentation](https://socketry.github.io/async-grpc-xds/) for more details.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
This is an early implementation focused on ADS with CDS and EDS. LDS/RDS, full routing semantics, NACK handling, locality weighting, and delta xDS are not complete yet.
|
|
13
|
+
- [Getting Started](https://socketry.github.io/async-grpc-xds/guides/getting-started/index) - This guide explains how to use `async-grpc-xds` to publish CDS and EDS resources to Envoy, or to discover gRPC backends from Ruby using xDS.
|
|
16
14
|
|
|
17
15
|
## Testing
|
|
18
16
|
|
|
19
|
-
The `
|
|
17
|
+
The `integration/` directory contains Docker Compose environments for testing the Ruby xDS client against a Go control plane and the Ruby control plane against Envoy.
|
|
20
18
|
|
|
21
19
|
``` bash
|
|
22
|
-
|
|
20
|
+
bundle exec bake test:integration
|
|
23
21
|
```
|
|
24
22
|
|
|
25
23
|
## Releases
|
|
26
24
|
|
|
27
25
|
Please see the [project releases](https://socketry.github.io/async-grpc-xds/releases/index) for all releases.
|
|
28
26
|
|
|
27
|
+
### v0.4.0
|
|
28
|
+
|
|
29
|
+
- Add dedicated Cluster Discovery Service and Endpoint Discovery Service implementations, allowing resource-specific xDS streams without claiming ADS.
|
|
30
|
+
- Allow generated clusters to use a dedicated EDS configuration source instead of ADS.
|
|
31
|
+
|
|
29
32
|
### v0.3.0
|
|
30
33
|
|
|
31
34
|
- Add Envoy HTTP active health-check resources and attach health checks to generated clusters.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.4.0
|
|
4
|
+
|
|
5
|
+
- Add dedicated Cluster Discovery Service and Endpoint Discovery Service implementations, allowing resource-specific xDS streams without claiming ADS.
|
|
6
|
+
- Allow generated clusters to use a dedicated EDS configuration source instead of ADS.
|
|
7
|
+
|
|
3
8
|
## v0.3.0
|
|
4
9
|
|
|
5
10
|
- Add Envoy HTTP active health-check resources and attach health checks to generated clusters.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-grpc-xds
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -126,17 +126,21 @@ executables: []
|
|
|
126
126
|
extensions: []
|
|
127
127
|
extra_rdoc_files: []
|
|
128
128
|
files:
|
|
129
|
-
-
|
|
130
|
-
-
|
|
129
|
+
- context/getting-started.md
|
|
130
|
+
- context/index.yaml
|
|
131
131
|
- lib/async/grpc/xds.rb
|
|
132
132
|
- lib/async/grpc/xds/ads_stream.rb
|
|
133
133
|
- lib/async/grpc/xds/client.rb
|
|
134
134
|
- lib/async/grpc/xds/client_side_weighted_round_robin.rb
|
|
135
135
|
- lib/async/grpc/xds/cluster.rb
|
|
136
|
+
- lib/async/grpc/xds/cluster_discovery_service.rb
|
|
137
|
+
- lib/async/grpc/xds/config_source.rb
|
|
136
138
|
- lib/async/grpc/xds/context.rb
|
|
137
139
|
- lib/async/grpc/xds/control_plane.rb
|
|
138
140
|
- lib/async/grpc/xds/discovery_client.rb
|
|
141
|
+
- lib/async/grpc/xds/discovery_service.rb
|
|
139
142
|
- lib/async/grpc/xds/endpoint.rb
|
|
143
|
+
- lib/async/grpc/xds/endpoint_discovery_service.rb
|
|
140
144
|
- lib/async/grpc/xds/health_checker.rb
|
|
141
145
|
- lib/async/grpc/xds/http_health_check.rb
|
|
142
146
|
- lib/async/grpc/xds/load_balancer.rb
|
|
@@ -144,6 +148,7 @@ files:
|
|
|
144
148
|
- lib/async/grpc/xds/resources.rb
|
|
145
149
|
- lib/async/grpc/xds/server.rb
|
|
146
150
|
- lib/async/grpc/xds/service.rb
|
|
151
|
+
- lib/async/grpc/xds/stream.rb
|
|
147
152
|
- lib/async/grpc/xds/version.rb
|
|
148
153
|
- lib/envoy.rb
|
|
149
154
|
- lib/envoy/annotations/deprecation_pb.rb
|
|
@@ -366,21 +371,12 @@ files:
|
|
|
366
371
|
- proto/xds/type/v3/typed_struct.proto
|
|
367
372
|
- readme.md
|
|
368
373
|
- releases.md
|
|
369
|
-
- xds/Dockerfile.backend
|
|
370
|
-
- xds/Dockerfile.control-plane
|
|
371
|
-
- xds/backend_server.rb
|
|
372
|
-
- xds/docker-compose.yaml
|
|
373
|
-
- xds/go.mod
|
|
374
|
-
- xds/go.sum
|
|
375
|
-
- xds/readme.md
|
|
376
|
-
- xds/test/async/grpc/xds/client.rb
|
|
377
|
-
- xds/test/async/grpc/xds/control_plane.rb
|
|
378
|
-
- xds/test_server.go
|
|
379
|
-
- xds/update_protos.sh
|
|
380
374
|
homepage: https://github.com/socketry/async-grpc-xds
|
|
381
375
|
licenses:
|
|
382
376
|
- MIT
|
|
383
377
|
metadata:
|
|
378
|
+
bug_tracker_uri: https://github.com/socketry/async-grpc-xds/issues
|
|
379
|
+
changelog_uri: https://github.com/socketry/async-grpc-xds/blob/main/releases.md
|
|
384
380
|
documentation_uri: https://socketry.github.io/async-grpc-xds/
|
|
385
381
|
source_code_uri: https://github.com/socketry/async-grpc-xds.git
|
|
386
382
|
rdoc_options: []
|
metadata.gz.sig
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
cLu*2�}=˙�?u�V��T�<)�|�D��M^Vi���ΔdKvH�!��v�����O3����S䰻�n�3ů]m���� �=-m9-P��Q+���8fP�_VMad���
|
|
2
|
+
M���ʟZ����A�|P��4<�j�4�#Y��D�R�8��H����Z�|������B�@4� �sb�����jO�!�}�Ys�H�����*`K��}�Û+��f�b�ŭ��:z��)�����6���<�f ��ܗ��G&�G�7�6nVYz��`"F睝��LzEv��%l{�F �uSD��o��k�"�x���T�E.���'����P����ō`�w!�_N]�!��s��
|
|
3
|
+
@[$���r��/
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2026, by Samuel Williams.
|
|
5
|
-
|
|
6
|
-
require "protocol/grpc/interface"
|
|
7
|
-
require_relative "test_message"
|
|
8
|
-
|
|
9
|
-
module Async
|
|
10
|
-
module GRPC
|
|
11
|
-
module Fixtures
|
|
12
|
-
# Test interface for unit tests
|
|
13
|
-
# RPC names use PascalCase to match .proto files
|
|
14
|
-
class TestInterface < Protocol::GRPC::Interface
|
|
15
|
-
rpc :UnaryCall, request_class: Protocol::GRPC::Fixtures::TestMessage,
|
|
16
|
-
response_class: Protocol::GRPC::Fixtures::TestMessage, streaming: :unary
|
|
17
|
-
rpc :ServerStreamingCall, request_class: Protocol::GRPC::Fixtures::TestMessage,
|
|
18
|
-
response_class: Protocol::GRPC::Fixtures::TestMessage, streaming: :server_streaming
|
|
19
|
-
rpc :SayHello, request_class: Protocol::GRPC::Fixtures::TestMessage,
|
|
20
|
-
response_class: Protocol::GRPC::Fixtures::TestMessage, streaming: :unary
|
|
21
|
-
rpc :BidirectionalCall, request_class: Protocol::GRPC::Fixtures::TestMessage,
|
|
22
|
-
response_class: Protocol::GRPC::Fixtures::TestMessage, streaming: :bidirectional
|
|
23
|
-
rpc :ClientStreamingCall, request_class: Protocol::GRPC::Fixtures::TestMessage,
|
|
24
|
-
response_class: Protocol::GRPC::Fixtures::TestMessage, streaming: :client_streaming
|
|
25
|
-
rpc :SlowCall
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Test service implementation
|
|
29
|
-
# Method names use snake_case (Ruby convention)
|
|
30
|
-
class TestService < Async::GRPC::Service
|
|
31
|
-
def unary_call(input, output, _call)
|
|
32
|
-
request = input.read
|
|
33
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Response: #{request.value}")
|
|
34
|
-
output.write(response)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def server_streaming_call(input, output, _call)
|
|
38
|
-
request = input.read
|
|
39
|
-
3.times do |i|
|
|
40
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Response #{i}: #{request.value}")
|
|
41
|
-
output.write(response)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def say_hello(input, output, _call)
|
|
46
|
-
request = input.read
|
|
47
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Hello, #{request.value}!")
|
|
48
|
-
output.write(response)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def bidirectional_call(input, output, _call)
|
|
52
|
-
# Read all input messages and echo them back with a prefix
|
|
53
|
-
input.each do |request|
|
|
54
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Echo: #{request.value}")
|
|
55
|
-
output.write(response)
|
|
56
|
-
end
|
|
57
|
-
output.close_write
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def client_streaming_call(input, output, _call)
|
|
61
|
-
# Read all input messages and return a summary
|
|
62
|
-
values = []
|
|
63
|
-
input.each do |request|
|
|
64
|
-
values << request.value
|
|
65
|
-
end
|
|
66
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Received: #{values.join(', ')}")
|
|
67
|
-
output.write(response)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def slow_call(input, output, _call)
|
|
71
|
-
request = input.read
|
|
72
|
-
sleep 1 # Simulate a slow operation
|
|
73
|
-
response = Protocol::GRPC::Fixtures::TestMessage.new(value: "Slow response: #{request.value}")
|
|
74
|
-
output.write(response)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2026, by Samuel Williams.
|
|
5
|
-
|
|
6
|
-
module Protocol
|
|
7
|
-
module GRPC
|
|
8
|
-
module Fixtures
|
|
9
|
-
# Simple test message for unit tests.
|
|
10
|
-
# Provides a basic protobuf-like message structure.
|
|
11
|
-
class TestMessage
|
|
12
|
-
# @attribute [String | Nil] The message value.
|
|
13
|
-
attr_accessor :value
|
|
14
|
-
|
|
15
|
-
# Initialize a new test message.
|
|
16
|
-
# @parameter value [String | Nil] The message value
|
|
17
|
-
def initialize(value: nil)
|
|
18
|
-
@value = value
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Serialize the message to a binary string.
|
|
22
|
-
# @returns [String] Binary representation of the message
|
|
23
|
-
def to_proto
|
|
24
|
-
# Simple serialization: length-prefixed value
|
|
25
|
-
value_data = (@value || "").dup.force_encoding(Encoding::BINARY)
|
|
26
|
-
[value_data.bytesize].pack("N") + value_data
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
alias encode to_proto
|
|
30
|
-
|
|
31
|
-
# Deserialize a binary string into a message.
|
|
32
|
-
# @parameter data [String] Binary representation of the message
|
|
33
|
-
# @returns [TestMessage] Deserialized message instance
|
|
34
|
-
def self.decode(data)
|
|
35
|
-
# Simple binary format: first 4 bytes are length, rest is value
|
|
36
|
-
length = data[0...4].unpack1("N")
|
|
37
|
-
value = data[4...(4 + length)].dup.force_encoding(Encoding::UTF_8)
|
|
38
|
-
new(value: value)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Check equality with another message.
|
|
42
|
-
# @parameter other [Object] The object to compare
|
|
43
|
-
# @returns [Boolean] `true` if values are equal
|
|
44
|
-
def ==(other)
|
|
45
|
-
other.is_a?(TestMessage) && @value == other.value
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Get a string representation of the message.
|
|
49
|
-
# @returns [String] String representation
|
|
50
|
-
def inspect
|
|
51
|
-
"#<#{self.class.name} value=#{@value.inspect}>"
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
data/xds/Dockerfile.backend
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
FROM ruby:latest
|
|
2
|
-
|
|
3
|
-
WORKDIR /app
|
|
4
|
-
ENV BUNDLE_GEMFILE=/app/gems.rb \
|
|
5
|
-
BUNDLE_WITHOUT=maintenance
|
|
6
|
-
|
|
7
|
-
# Install dependencies
|
|
8
|
-
RUN apt-get update && apt-get install -y \
|
|
9
|
-
build-essential \
|
|
10
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
11
|
-
|
|
12
|
-
# Copy gemfile, gemspec, and minimal lib files needed for gemspec.
|
|
13
|
-
COPY gems.rb *.gemspec ./
|
|
14
|
-
COPY lib/async/grpc/xds/version.rb lib/async/grpc/xds/version.rb
|
|
15
|
-
RUN bundle install
|
|
16
|
-
|
|
17
|
-
# Copy application code
|
|
18
|
-
COPY . .
|
|
19
|
-
|
|
20
|
-
# Expose port
|
|
21
|
-
EXPOSE ${PORT:-50051}
|
|
22
|
-
|
|
23
|
-
# Run gRPC server
|
|
24
|
-
CMD bundle exec ruby xds/backend_server.rb
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
FROM golang:1.21-alpine AS builder
|
|
2
|
-
|
|
3
|
-
# Install build dependencies
|
|
4
|
-
RUN apk add --no-cache git
|
|
5
|
-
|
|
6
|
-
WORKDIR /build
|
|
7
|
-
|
|
8
|
-
COPY go.mod go.sum ./
|
|
9
|
-
RUN go mod download
|
|
10
|
-
|
|
11
|
-
COPY test_server.go ./
|
|
12
|
-
RUN go build -o /xds-test-server test_server.go
|
|
13
|
-
|
|
14
|
-
FROM alpine:latest
|
|
15
|
-
|
|
16
|
-
RUN apk add --no-cache netcat-openbsd ca-certificates
|
|
17
|
-
|
|
18
|
-
COPY --from=builder /xds-test-server /xds-test-server
|
|
19
|
-
|
|
20
|
-
EXPOSE 18000 18001
|
|
21
|
-
|
|
22
|
-
CMD ["/xds-test-server", "-port", "18000"]
|