rails_twirp 0.5.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8df8457b09993d7d5c986130e724948df049c201b6797f33a7b66458bde98918
4
- data.tar.gz: 0a2100cbefd37754f9dbd6cf666def1c29d0936322f72837d7e60653b5510b79
3
+ metadata.gz: '054689e120dd41594071de17cd6e8967886699ec4f75bd08aceae475a2e12e03'
4
+ data.tar.gz: 56b1471b8103f249c9c2d53fe78b2aa31a978c67f3a1b658e15923534a4a3b63
5
5
  SHA512:
6
- metadata.gz: 1b50c23cd6fa8852686ca96066c0a65a532f06ec0225b5ed04ac860218760d187e868d0b3d499855527ed23d355dacf8bf33eb1aaf2fd1b590b29aa12c8e836a
7
- data.tar.gz: 461fe47bbafdd0bcf304f48b4938f307fd380d7bbce7049a703c60f7bc781b0f58b1cf06b7410c4a168e39441b1a9bd49b5091a0dbfc3472870c002bef6f51e1
6
+ metadata.gz: b3630e5152913b1bca04ca94ab0d15bdce29f6853a4cafb226c4e5f678042e8a1bbcd6e931b20432d816556ef5f087512e4ad09327e5bbfa3af72e97bcce9a5f
7
+ data.tar.gz: bace8057362c6085ba5edea873087b5b4459f6c0dc48e5abeea589380abcd64386dfedfcd41cc2a841f69721b3d852a8516aaf06522df843d8b09e902879842e
data/Gemfile CHANGED
@@ -4,5 +4,6 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem "sqlite3"
7
- gem "pbbuilder", "~> 0.3.0"
7
+ gem "pbbuilder", "~> 0.10.0"
8
8
  gem "standard"
9
+ gem "pry"
@@ -10,6 +10,8 @@ require "abstract_controller/callbacks"
10
10
  require "action_controller/metal/helpers"
11
11
  require "rails_twirp/rescue"
12
12
  require "rails_twirp/url_for"
13
+ require "rails_twirp/implicit_render"
14
+ require "rails_twirp/instrumentation"
13
15
 
14
16
  module RailsTwirp
15
17
  class Base < AbstractController::Base
@@ -24,15 +26,16 @@ module RailsTwirp
24
26
  include UrlFor
25
27
  include AbstractController::AssetPaths
26
28
  include AbstractController::Caching
27
- include AbstractController::Logger
28
29
 
29
30
  include ActionView::Rendering
30
31
  include RenderPb
31
32
  include Errors
33
+ include ImplicitRender
32
34
 
33
35
  # These need to be last so errors can be handled as early as possible.
34
36
  include AbstractController::Callbacks
35
37
  include Rescue
38
+ include Instrumentation
36
39
 
37
40
  attr_internal :request, :env, :response_class
38
41
  def initialize
@@ -55,8 +58,6 @@ module RailsTwirp
55
58
 
56
59
  process(action)
57
60
 
58
- # Implicit render
59
- self.response_body = render unless response_body
60
61
  response_body
61
62
  end
62
63
 
@@ -0,0 +1,11 @@
1
+ require "action_controller/metal/basic_implicit_render"
2
+
3
+ module RailsTwirp
4
+ module ImplicitRender
5
+ include ActionController::BasicImplicitRender
6
+
7
+ def default_render
8
+ render
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ module RailsTwirp
2
+ module Instrumentation
3
+ extend ActiveSupport::Concern
4
+
5
+ include AbstractController::Logger
6
+
7
+ def process_action(*)
8
+ raw_payload = {
9
+ controller: self.class.name,
10
+ action: action_name,
11
+ request: request,
12
+ http_request: http_request,
13
+ headers: http_request.headers,
14
+ path: http_request.fullpath
15
+ }
16
+
17
+ ActiveSupport::Notifications.instrument("start_processing.rails_twirp", raw_payload)
18
+
19
+ ActiveSupport::Notifications.instrument("process_action.rails_twirp", raw_payload) do |payload|
20
+ result = super
21
+ if response_body.is_a?(Twirp::Error)
22
+ payload[:code] = response_body.code
23
+ payload[:msg] = response_body.msg
24
+ else
25
+ payload[:code] = :success
26
+ end
27
+ payload[:response] = response_body
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ require "active_support/log_subscriber"
2
+
3
+ module RailsTwirp
4
+ class LogSubscriber < ActiveSupport::LogSubscriber
5
+ def start_processing(event)
6
+ return unless logger.info?
7
+
8
+ payload = event.payload
9
+
10
+ info "Processing by #{payload[:controller]}##{payload[:action]}"
11
+ end
12
+
13
+ def process_action(event)
14
+ payload = event.payload
15
+ exception_raised(payload[:http_request], payload[:exception_object]) if payload[:exception_object]
16
+
17
+ info do
18
+ code = payload.fetch(:code, :internal)
19
+
20
+ message = +"Completed #{code} in #{event.duration.round}ms (Allocations: #{event.allocations})"
21
+ message << "\n\n" if defined?(Rails.env) && Rails.env.development?
22
+
23
+ message
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def exception_raised(request, exception)
30
+ backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
31
+ wrapper = ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception)
32
+
33
+ log_error(wrapper)
34
+ end
35
+
36
+ def log_error(wrapper)
37
+ exception = wrapper.exception
38
+ trace = wrapper.exception_trace
39
+
40
+ message = []
41
+ message << " "
42
+ message << "#{exception.class} (#{exception.message}):"
43
+ message.concat(exception.annotated_source_code) if exception.respond_to?(:annotated_source_code)
44
+ message << " "
45
+ message.concat(trace)
46
+
47
+ log_array(message)
48
+ end
49
+
50
+ def log_array(array)
51
+ lines = Array(array)
52
+
53
+ return if lines.empty?
54
+
55
+ if logger.formatter&.respond_to?(:tags_text)
56
+ fatal { lines.join("\n#{logger.formatter.tags_text}") }
57
+ else
58
+ fatal { lines.join("\n") }
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ RailsTwirp::LogSubscriber.attach_to :rails_twirp
@@ -50,13 +50,13 @@ module RailsTwirp
50
50
  method_name = rpc_info[:ruby_method]
51
51
 
52
52
  # Stolen from Rails in ActionDispatch::Request#controller_class_for
53
- controller_name = mapping.controller.underscore
54
- const_name = controller_name.camelize << "Controller"
55
53
  action_name = mapping.action
56
54
  response_class = rpc_info[:output_class]
57
55
 
58
56
  handler.define_method(method_name) do |req, env|
59
- controller_class = ::ActiveSupport::Dependencies.constantize(const_name)
57
+ controller_name = mapping.controller.underscore
58
+ const_name = controller_name.camelize << "Controller"
59
+ controller_class = const_name.constantize
60
60
  controller_class.dispatch(action_name, req, response_class, env)
61
61
  end
62
62
  end
@@ -1,6 +1,13 @@
1
+ require "twirp/encoding"
2
+
1
3
  module RailsTwirp
2
4
  class IntegrationTest < ActiveSupport::TestCase
5
+ DEFAULT_HOST = "www.example.com"
6
+ Response = Struct.new(:status, :body, :headers)
7
+
3
8
  attr_reader :response, :request, :controller
9
+ attr_writer :mount_path
10
+ alias_method :mount_path!, :mount_path=
4
11
 
5
12
  def initialize(name)
6
13
  super
@@ -8,9 +15,27 @@ module RailsTwirp
8
15
  @before_rpc = []
9
16
  end
10
17
 
18
+ def host
19
+ @host || DEFAULT_HOST
20
+ end
21
+ attr_writer :host
22
+ alias_method :host!, :host=
23
+
24
+ def https?
25
+ @https
26
+ end
27
+
28
+ def https!(value = true)
29
+ @https = value
30
+ end
31
+
11
32
  def reset!
12
33
  @request = nil
13
34
  @response = nil
35
+ @host = nil
36
+ @host = nil
37
+ @https = false
38
+ @mount_path = "/twirp"
14
39
  end
15
40
 
16
41
  def before_rpc(&block)
@@ -19,32 +44,63 @@ module RailsTwirp
19
44
 
20
45
  def rpc(service, rpc, request, headers: nil)
21
46
  @request = request
22
- service = app.twirp.routes.services[service].to_service
23
-
24
- rack_env = {
25
- "HTTP_HOST" => "localhost"
26
- }
27
- http_request = ActionDispatch::Request.new(rack_env)
28
- http_request.headers.merge! headers if headers.present?
29
- env = {rack_env: rack_env}
30
47
 
48
+ env = build_rack_env(service, rpc, request, headers)
31
49
  @before_rpc.each do |hook|
32
50
  hook.call(env)
33
51
  end
34
52
 
35
- response = begin
36
- service.call_rpc rpc, request, env
37
- rescue => e
38
- Twirp::Error.internal_with(e)
39
- end
53
+ status, headers, body = app.call(env)
54
+ @response = decode_rack_response(service, rpc, status, headers, body)
55
+ set_controller_from_rack_env(env)
40
56
 
41
- @response = response
42
- @controller = http_request.controller_instance
43
- response
57
+ @response
44
58
  end
45
59
 
46
60
  def app
47
61
  RailsTwirp.test_app
48
62
  end
63
+
64
+ private
65
+
66
+ def build_rack_env(service, rpc, request, headers)
67
+ env = {
68
+ "CONTENT_TYPE" => request_content_type,
69
+ "HTTPS" => https? ? "on" : "off",
70
+ "HTTP_HOST" => host,
71
+ "PATH_INFO" => "#{@mount_path}/#{service.service_full_name}/#{rpc}",
72
+ "REQUEST_METHOD" => "POST",
73
+ "SERVER_NAME" => host,
74
+ "SERVER_PORT" => https? ? "443" : "80",
75
+ "rack.url_scheme" => https? ? "https" : "http"
76
+ }
77
+ if headers.present?
78
+ http_request = ActionDispatch::Request.new(env)
79
+ http_request.headers.merge! headers
80
+ end
81
+
82
+ input_class = service.rpcs[rpc][:input_class]
83
+ env["rack.input"] = StringIO.new(Twirp::Encoding.encode(request, input_class, request_content_type))
84
+ env
85
+ end
86
+
87
+ def request_content_type
88
+ Twirp::Encoding::PROTO
89
+ end
90
+
91
+ def decode_rack_response(service, rpc, status, headers, body)
92
+ body = body.join # body is an Enumerable
93
+
94
+ if status === 200
95
+ output_class = service.rpcs[rpc][:output_class]
96
+ Twirp::Encoding.decode(body, output_class, headers["Content-Type"])
97
+ else
98
+ Twirp::Client.error_from_response(Response.new(status, body, headers))
99
+ end
100
+ end
101
+
102
+ def set_controller_from_rack_env(env)
103
+ @controller = ActionDispatch::Request.new(env).controller_class
104
+ end
49
105
  end
50
106
  end
@@ -1,3 +1,3 @@
1
1
  module RailsTwirp
2
- VERSION = "0.5.0"
2
+ VERSION = "0.7.2"
3
3
  end
data/lib/rails_twirp.rb CHANGED
@@ -4,6 +4,7 @@ require "rails_twirp/application"
4
4
  require "rails_twirp/base"
5
5
  require "rails_twirp/route_set"
6
6
  require "rails_twirp/testing/integration_test"
7
+ require "rails_twirp/log_subscriber"
7
8
 
8
9
  module RailsTwirp
9
10
  mattr_accessor :test_app
data/rails_twirp.gemspec CHANGED
@@ -12,6 +12,6 @@ Gem::Specification.new do |spec|
12
12
  spec.files = `git ls-files`.split("\n")
13
13
  spec.test_files = `git ls-files -- test/*`.split("\n")
14
14
 
15
- spec.add_dependency "rails", "~> 6.1.3"
15
+ spec.add_dependency "rails", ">= 6.1.3"
16
16
  spec.add_dependency "twirp", "~> 1.7.2"
17
17
  end
@@ -1,4 +1,4 @@
1
- require "api_twirp"
1
+ require_relative "../../proto/api_twirp"
2
2
 
3
3
  Rails.application.twirp.routes.draw do
4
4
  service RPC::DummyAPI::DummyService do
@@ -11,7 +11,16 @@ class PingControllerTest < RailsTwirp::IntegrationTest
11
11
  req = RPC::DummyAPI::PingRequest.new(name: "Bouke")
12
12
  rpc RPC::DummyAPI::DummyService, "PingRender", req
13
13
  refute_instance_of Twirp::Error, response
14
- assert_equal "http://localhost/twirp BoukeBouke", response.double_name
14
+ assert_equal "http://www.example.com/twirp BoukeBouke", response.double_name
15
+ end
16
+
17
+ test "you can ping render with host and https" do
18
+ host! "localhost"
19
+ https!
20
+ req = RPC::DummyAPI::PingRequest.new(name: "Bouke")
21
+ rpc RPC::DummyAPI::DummyService, "PingRender", req
22
+ refute_instance_of Twirp::Error, response
23
+ assert_equal "https://localhost/twirp BoukeBouke", response.double_name
15
24
  end
16
25
 
17
26
  test "you can ping template" do
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_twirp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bouke van der Bijl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-20 00:00:00.000000000 Z
11
+ date: 2021-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 6.1.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.1.3
27
27
  - !ruby/object:Gem::Dependency
@@ -59,6 +59,9 @@ files:
59
59
  - lib/rails_twirp/base.rb
60
60
  - lib/rails_twirp/engine.rb
61
61
  - lib/rails_twirp/errors.rb
62
+ - lib/rails_twirp/implicit_render.rb
63
+ - lib/rails_twirp/instrumentation.rb
64
+ - lib/rails_twirp/log_subscriber.rb
62
65
  - lib/rails_twirp/mapper.rb
63
66
  - lib/rails_twirp/render_pb.rb
64
67
  - lib/rails_twirp/rescue.rb
@@ -151,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
154
  - !ruby/object:Gem::Version
152
155
  version: '0'
153
156
  requirements: []
154
- rubygems_version: 3.2.3
157
+ rubygems_version: 3.2.22
155
158
  signing_key:
156
159
  specification_version: 4
157
160
  summary: Integrate Twirp into Rails