Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement protocol plugin and rpcv2 protocol #264

Merged
merged 75 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
a57acd6
Add protocol base class and draft rpcv2 protocol implementation
jterapin Feb 3, 2025
4d3a7f4
Add example implementation of codegenerated plugin
jterapin Feb 3, 2025
036d2d8
Update smithy model to use rpcv2 trait for testing
jterapin Feb 3, 2025
fb17908
Add projections
jterapin Feb 3, 2025
c7c672c
Merge decaf into branch
jterapin Feb 4, 2025
787f763
Update RPCV2 protocol
jterapin Feb 5, 2025
37c2508
Add protocols weld
jterapin Feb 6, 2025
578478e
Update protocol weld
jterapin Feb 6, 2025
c168be0
Update protocol weld to include a TODO
jterapin Feb 6, 2025
2d098e4
Add more TODO guidance
jterapin Feb 6, 2025
885ae8b
Update protocol plugin
jterapin Feb 6, 2025
20abd06
Update protocol plugin and other components
jterapin Feb 6, 2025
aa367c8
Update handler syntax
jterapin Feb 6, 2025
589feaa
Appease specs
jterapin Feb 6, 2025
8e4c0f3
Update projections
jterapin Feb 6, 2025
03e7699
Remove base class
jterapin Feb 6, 2025
318b0cd
Remove unnecessary method
jterapin Feb 6, 2025
c29eb20
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 7, 2025
d5413e6
Update protocol modules
jterapin Feb 7, 2025
68713d1
Update documentation
jterapin Feb 7, 2025
5418ba0
Update endpoint specs to handle protocol plugin
jterapin Feb 7, 2025
1f475c2
Move handler classes to smithy-client
jterapin Feb 10, 2025
42114fa
Updates based on feedbacks
jterapin Feb 10, 2025
2656ba7
Sync fixtures
jterapin Feb 10, 2025
86c777d
Update handlers
jterapin Feb 10, 2025
2014c1c
Add rbs file
jterapin Feb 10, 2025
1a26319
Revert "Sync fixtures"
jterapin Feb 10, 2025
1ed8b04
Add protocol plugin specs
jterapin Feb 10, 2025
f7922a9
Update fixture model to recongize config file
jterapin Feb 10, 2025
a4ef87c
update projections
jterapin Feb 10, 2025
f4cb90d
Revert "Update fixture model to recongize config file"
jterapin Feb 10, 2025
fd361e9
Fix config flag for fixtures
jterapin Feb 10, 2025
659a1ea
Fix documentation
jterapin Feb 11, 2025
f3360c3
Merge decaf into branch
jterapin Feb 11, 2025
7952f0e
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 11, 2025
b4354a9
Update plugin docs
jterapin Feb 11, 2025
44f1898
Fix config documentation
jterapin Feb 11, 2025
4b1ed95
Fix specs based on merged changes
jterapin Feb 11, 2025
15cf0aa
Handle endpoints
jterapin Feb 11, 2025
9a9afb6
Resolve failures relating to content-type and accept headers
jterapin Feb 11, 2025
3f35c47
Add shapes change coverage
jterapin Feb 11, 2025
69208d9
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 11, 2025
0edce81
Fix codec deserialization
jterapin Feb 11, 2025
046227d
Add possible rbs fix
jterapin Feb 11, 2025
0687fd4
Add header fixes
jterapin Feb 11, 2025
7a9a8f3
Update rbs
jterapin Feb 11, 2025
e05f941
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 14, 2025
3bc1683
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 17, 2025
8e201a6
Merge decaf into branch
jterapin Feb 17, 2025
0ae5b87
Adding member names to shape
jterapin Feb 17, 2025
36fe4a5
Update based on refactor
jterapin Feb 17, 2025
c175478
Merge decaf into branch
jterapin Feb 17, 2025
936d4ec
Temp fix
jterapin Feb 17, 2025
d3875d1
Add to reference service shape name
jterapin Feb 18, 2025
eb3255a
Fix failures related to protocol tests
jterapin Feb 18, 2025
c5adb00
Fix top model changes
jterapin Feb 18, 2025
a65325d
Fix rbs
jterapin Feb 18, 2025
cebe5c4
Appease rubocop
jterapin Feb 18, 2025
70dd666
Update syntax
jterapin Feb 20, 2025
52a8d15
Update helpful commands
jterapin Feb 20, 2025
fcb34b1
Update schema and its shapes
jterapin Feb 20, 2025
bd0d912
Update cbor
jterapin Feb 20, 2025
f7358e5
Merge branch 'decaf' into add_cbor_protocol
jterapin Feb 21, 2025
402f07a
Clean up README
jterapin Feb 21, 2025
86995e0
Update Protocol Plugin to hold generic handlers
jterapin Feb 21, 2025
8a29c33
Update based on feedbacks
jterapin Feb 21, 2025
668d9b0
Add DummyWeldProtocol
jterapin Feb 21, 2025
cafe0a9
Fix failure
jterapin Feb 21, 2025
37ca72d
Update existing spec const
jterapin Feb 21, 2025
7d590d8
Fix protocol test failures
jterapin Feb 21, 2025
3ec2dd0
Add members by name to shapes with members
jterapin Feb 22, 2025
75837df
Remove dup method
jterapin Feb 22, 2025
7ba096f
Refactor protocol weld tests
mullermp Feb 22, 2025
8ea5ea0
Refactor weld testing with protocol welds
mullermp Feb 22, 2025
0ab8632
Fix build
mullermp Feb 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions gems/smithy-client/lib/smithy-client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
require_relative 'smithy-client/cbor'
require_relative 'smithy-client/codecs/cbor'

# protocols
require_relative 'smithy-client/protocols'
require_relative 'smithy-client/protocols/rpcv2'

module Smithy
# Base module for a generated Smithy gem.
module Client
Expand Down
3 changes: 2 additions & 1 deletion gems/smithy-client/lib/smithy-client/codecs/cbor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def serialize(data, shape)
# @param [Struct] type
# @return [Object, Hash]
def deserialize(bytes, shape, type = nil)
return {} if bytes.empty?
return {} # for development purposes since default response body is StringIO
# return {} if bytes.empty?

parse_data(Client::CBOR.decode(bytes), shape, type)
end
Expand Down
5 changes: 5 additions & 0 deletions gems/smithy-client/lib/smithy-client/handler_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class HandlerContext
# @option options [Configuration] :config (nil)
# @option options [Request] :request (HTTP::Request.new)
# @option options [Response] :response (HTTP::Response.new)
# @option options [Protocol] :protocol (nil)
# @options options [Hash] :metadata ({})
def initialize(options = {})
@operation_name = options[:operation_name]
Expand All @@ -20,6 +21,7 @@ def initialize(options = {})
@config = options[:config]
@request = options[:request] || HTTP::Request.new
@response = options[:response] || HTTP::Response.new
@protocol = options[:protocol]
@metadata = {}
end

Expand All @@ -44,6 +46,9 @@ def initialize(options = {})
# @return [Response]
attr_accessor :response

# @return [Protocol]
attr_accessor :protocol

# @return [Hash]
attr_reader :metadata

Expand Down
31 changes: 31 additions & 0 deletions gems/smithy-client/lib/smithy-client/protocols.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Smithy
module Client
module Protocols
# Base protocol class that all protocols derived from
class ProtocolBase
def initialize(id)
@id = id
@service_id = nil
end

attr_reader :id

attr_accessor :service_id

def build_request(context)
raise NotImplementedError
end

def parse_response(context)
raise NotImplementedError
end

def parse_error
raise NotImplementedError
end
end
end
end
end
50 changes: 50 additions & 0 deletions gems/smithy-client/lib/smithy-client/protocols/rpcv2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module Smithy
module Client
module Protocols
# RPCV2 protocol
class RPCV2 < ProtocolBase
def initialize
super('smithy.protocols#rpcv2Cbor')
end

def build_request(context)
puts 'BUILDING REQUEST FROM RPCV2 PROTOCOL'
input_shape = context.operation.input
context.request.http_method = 'POST'
codec = Client::Codecs::CBOR.new(codec_setting(input_shape))
context.request.body = codec.serialize(context.params, input_shape)
apply_headers(context.request)
end

def parse_response(context)
puts 'PARSING RESPONSE FROM RPCV2 PROTOCOL'
# TODO: Need to refactor to handle eventstreams
output_shape = context.operation.output
codec = Client::Codecs::CBOR.new(codec_setting(output_shape))
codec.deserialize(context.response.body, output_shape, output_shape.type)
end

# TODO: Implement ContentType Handler specific to RPCV2
def apply_content_type(context)
context.request.headers['Content-Type'] = 'application/cbor'
end

private

def apply_headers(request)
# TODO: Add X-Amz-Query-Mode header if aws.protocols#awsQueryCompatible is true
request.headers['Smithy-Protocol'] = 'rpc-v2-cbor'
# TODO: Remove after implementing ContentLength Plugin/Handler
request.headers['Content-Length'] = request.body.size
end

def codec_setting(_shape)
# TODO: Filter codec traits, depending on context
{}
end
end
end
end
end
5 changes: 5 additions & 0 deletions gems/smithy/lib/smithy/generators/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ def code_generated_plugins
require_path: "lib/#{@gem_name}/plugins/endpoint.rb",
source: Views::Client::EndpointPlugin.new(@plan).render
)
e.yield Views::Client::Plugin.new(
class_name: "#{@plan.module_name}::Plugins::Protocol",
require_path: "lib/#{@gem_name}/plugins/protocol.rb",
source: Views::Client::ProtocolPlugin.new(@plan).render
)
end
end

Expand Down
5 changes: 4 additions & 1 deletion gems/smithy/lib/smithy/templates/client/client.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@ module <%= module_name %>

def build_input(operation_name, params)
handlers = @handlers.for(operation_name)
operation = config.schema.operation(operation_name)
config.protocol.service_id = '<%= service_id %>'
context = Smithy::Client::HandlerContext.new(
operation_name: operation_name,
operation: config.schema.operation(operation_name),
operation: operation,
client: self,
params: params,
config: config,
protocol: config.protocol
)
context[:gem_name] = '<%= gem_name %>'
context[:gem_version] = '<%= gem_version %>'
Expand Down
43 changes: 43 additions & 0 deletions gems/smithy/lib/smithy/templates/client/protocol_plugin.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

# This is generated code!

module <%= module_name %>
module Plugins
# Protocol plugin
class Protocol < Smithy::Client::Plugin
option(
:protocol,
doc_default: 'Smithy::Client::Protocols::<%= protocol_name %>',
doc_type: 'Smithy::Client::Protocols::ProtocolBase',
docstring: 'TODO'
) do |_cfg|
Smithy::Client::Protocols::<%= protocol_name %>.new
end

# @api private
class Build < Smithy::Client::Handler
def call(context)
puts '**Calling from BuildHandler**'
context.protocol.build_request(context)
@handler.call(context)
end
end

# @api private
class Parse < Smithy::Client::Handler
def call(context)
puts '**Calling from ParseHandler**'
resp = @handler.call(context)
context.protocol.parse_response(context)
resp
end
end

def add_handlers(handlers, config)
handlers.add(Build)
handlers.add(Parse)
end
end
end
end
1 change: 1 addition & 0 deletions gems/smithy/lib/smithy/views/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module Client; end
require_relative 'client/gemspec'
require_relative 'client/module'
require_relative 'client/module_rbs'
require_relative 'client/protocol_plugin'
require_relative 'client/rubocop_yml'
require_relative 'client/shapes'
require_relative 'client/shapes_rbs'
Expand Down
4 changes: 4 additions & 0 deletions gems/smithy/lib/smithy/views/client/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ def module_name
@plan.module_name
end

def service_id
@plan.service.keys.first
end

def gem_name
@plan.gem_name
end
Expand Down
12 changes: 11 additions & 1 deletion gems/smithy/lib/smithy/views/client/module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,17 @@ def requires
return %i[customizations types shapes] if @plan.type == :schema

# Order matters here - plugins must come before client, types must come before shapes
%w[plugins/endpoint types shapes client customizations errors endpoint_parameters endpoint_provider]
%w[
plugins/endpoint
plugins/protocol
types
shapes
client
customizations
errors
endpoint_parameters
endpoint_provider
]
end
end
end
Expand Down
45 changes: 45 additions & 0 deletions gems/smithy/lib/smithy/views/client/protocol_plugin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

module Smithy
module Views
module Client
# @api private
class ProtocolPlugin < View
def initialize(plan)
@plan = plan
@model = plan.model
super()
end

attr_reader :plan

def module_name
@plan.module_name
end

def protocol_name
raise ArgumentError, 'Invalid protocol' if (protocol = resolve_protocol).nil?

protocol
end

private

SUPPORTED_PROTOCOLS = {
'smithy.protocols#rpcv2Cbor' => 'RPCV2'
}.freeze

# smithy.protocols#rpcv2Cbor
def resolve_protocol
protocol = @plan
.service
.values
.first['traits']
.find { |k, _v| k.start_with?('smithy.protocols') }
&.first
SUPPORTED_PROTOCOLS[protocol]
end
end
end
end
end
3 changes: 3 additions & 0 deletions model/weather.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ $version: "2"

namespace example.weather

use smithy.protocols#rpcv2Cbor

/// Provides weather forecasts.
@rpcv2Cbor
@paginated(inputToken: "nextToken", outputToken: "nextToken", pageSize: "pageSize")
service Weather {
version: "2006-03-01"
Expand Down
1 change: 1 addition & 0 deletions projections/weather/lib/weather.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Weather
end

require_relative 'weather/plugins/endpoint'
require_relative 'weather/plugins/protocol'
require_relative 'weather/types'
require_relative 'weather/shapes'
require_relative 'weather/client'
Expand Down
10 changes: 8 additions & 2 deletions projections/weather/lib/weather/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Client < Smithy::Client::Base

add_plugin(Smithy::Client::Plugins::NetHTTP)
add_plugin(Weather::Plugins::Endpoint)
add_plugin(Weather::Plugins::Protocol)

# @param [Hash] options
# @option options [Logger] :logger
Expand Down Expand Up @@ -83,6 +84,8 @@ class Client < Smithy::Client::Base
# `#resolve_endpoint(parameters)`.
# @option options [String] :endpoint
# Custom Endpoint
# @option options [Smithy::Client::Protocols::ProtocolBase] :protocol (Smithy::Client::Protocols::RPCV2)
# TODO
def initialize(*args)
super
end
Expand Down Expand Up @@ -164,12 +167,15 @@ def list_cities(params = {}, options = {})

def build_input(operation_name, params)
handlers = @handlers.for(operation_name)
operation = config.schema.operation(operation_name)
config.protocol.service_id = 'example.weather#Weather'
context = Smithy::Client::HandlerContext.new(
operation_name: operation_name,
operation: config.schema.operation(operation_name),
operation: operation,
client: self,
params: params,
config: config
config: config,
protocol: config.protocol
)
context[:gem_name] = 'weather'
context[:gem_version] = '1.0.0'
Expand Down
43 changes: 43 additions & 0 deletions projections/weather/lib/weather/plugins/protocol.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

# This is generated code!

module Weather
module Plugins
# Protocol plugin
class Protocol < Smithy::Client::Plugin
option(
:protocol,
doc_default: 'Smithy::Client::Protocols::RPCV2',
doc_type: 'Smithy::Client::Protocols::ProtocolBase',
docstring: 'TODO'
) do |_cfg|
Smithy::Client::Protocols::RPCV2.new
end

# @api private
class Build < Smithy::Client::Handler
def call(context)
puts '**Calling from BuildHandler**'
context.protocol.build_request(context)
@handler.call(context)
end
end

# @api private
class Parse < Smithy::Client::Handler
def call(context)
puts '**Calling from ParseHandler**'
resp = @handler.call(context)
context.protocol.parse_response(context)
resp
end
end

def add_handlers(handlers, _config)
handlers.add(Build)
handlers.add(Parse)
end
end
end
end
2 changes: 1 addition & 1 deletion projections/weather/lib/weather/shapes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ module Shapes
schema.service = ServiceShape.new(
id: 'example.weather#Weather',
version: '2006-03-01',
traits: { 'smithy.api#paginated' => { 'inputToken' => 'nextToken', 'outputToken' => 'nextToken', 'pageSize' => 'pageSize' } }
traits: { 'smithy.api#paginated' => { 'inputToken' => 'nextToken', 'outputToken' => 'nextToken', 'pageSize' => 'pageSize' }, 'smithy.protocols#rpcv2Cbor' => {} }
)
schema.add_operation(:get_city, OperationShape.new do |operation|
operation.id = 'example.weather#GetCity'
Expand Down
Loading
Loading