rails_twirp 0.5.0 → 0.7.2

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 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