twirp-on-rails 1.2.0 → 1.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
- data/CHANGELOG.md +7 -0
- data/Gemfile +5 -1
- data/README.md +18 -0
- data/lib/twirp/rails/configuration.rb +11 -0
- data/lib/twirp/rails/engine.rb +25 -14
- data/lib/twirp/rails/error.rb +8 -0
- data/lib/twirp/rails/handler.rb +2 -0
- data/lib/twirp/rails/logger.rb +31 -0
- data/lib/twirp/rails/version.rb +1 -1
- data/lib/twirp/rails.rb +22 -23
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4525c9180d9b5ee9316453fefadc8982793f5aee3ebe55db5136fb2970e3b764
|
4
|
+
data.tar.gz: 68cb9924021caeefa024616b0d68d28a4a20ec77bf663b658be973fbb9fea86b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 545989b2edaa3b4e78291f6847042e0728053e677b2e144e5b0463bdc5e00acd86fd0ea95ff8de6ae3ff19a12ac99d3941e325a27188a2f2fb0e4b23e787d9f4
|
7
|
+
data.tar.gz: 9075fd125690021fa6c1f192f0474fcc53639677cfa4c08904a20e7d31c1fbd487773ac227d42200c3e7e894b4ba9605486b017400d64c6c12bdd8cc455e96fc
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -9,7 +9,11 @@ gem "rake"
|
|
9
9
|
|
10
10
|
gem "debug"
|
11
11
|
gem "rspec-rails"
|
12
|
-
gem "sqlite3", "~> 1.4"
|
13
12
|
gem "standard", ">= 1.35.1"
|
14
13
|
gem "standard-performance"
|
15
14
|
gem "standard-rails"
|
15
|
+
|
16
|
+
# These standard library gems need to be here for with certain Rails 7/Ruby 3.4 combinations. Delete eventually.
|
17
|
+
gem "mutex_m"
|
18
|
+
gem "bigdecimal"
|
19
|
+
gem "drb"
|
data/README.md
CHANGED
@@ -151,6 +151,22 @@ As an Engine, we avoid all the standard Rails middleware. That's nice for simpli
|
|
151
151
|
Rails.application.config.twirp.middleware = [Rack::Deflater]
|
152
152
|
```
|
153
153
|
|
154
|
+
### Logging
|
155
|
+
|
156
|
+
Our built-in logging outputs the result of each request.
|
157
|
+
|
158
|
+
You could replace our logger if you want different output:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
Rails.application.config.twirp.logger = Rack::CommonLogger
|
162
|
+
```
|
163
|
+
|
164
|
+
Additionally, you can log the full Twirp response object to help with debugging:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
Rails.application.config.twirp.verbose_logging = true
|
168
|
+
```
|
169
|
+
|
154
170
|
## Bonus Features
|
155
171
|
|
156
172
|
Outside the [Twirp spec](https://twitchtv.github.io/twirp/docs/spec_v7.html), we have some (optional) extra magic. They might be useful to you, but you can easily ignore them too.
|
@@ -170,6 +186,8 @@ Rails.application.config.twirp.middleware = [
|
|
170
186
|
]
|
171
187
|
```
|
172
188
|
|
189
|
+
Note: The Handler will still be run, but you won't need to send back the response. Make sure your RPC is idempotent! Future versions hope to make it easier to short-circuit expensive parts of the handler.
|
190
|
+
|
173
191
|
## TODO
|
174
192
|
|
175
193
|
* More docs!
|
@@ -9,6 +9,15 @@ module Twirp
|
|
9
9
|
# Where to mount twirp routes. Defaults to /twirp
|
10
10
|
attr_accessor :endpoint
|
11
11
|
|
12
|
+
# Logger to use for Twirp requests. Defaults to Rails.logger
|
13
|
+
attr_accessor :logger
|
14
|
+
|
15
|
+
# Whether to log full Twirp responses. Can be useful for debugging, but can expose sensitive data.
|
16
|
+
# Defauts to false
|
17
|
+
# Example:
|
18
|
+
# Twirp Response: <Twirp::Example::Haberdasher::Hat: inches: 24, color: "Tan", name: "Pork Pie">
|
19
|
+
attr_accessor :verbose_logging
|
20
|
+
|
12
21
|
# An array of directories to search for *_twirp.rb files
|
13
22
|
# Defaults to ["lib"]
|
14
23
|
attr_accessor :load_paths
|
@@ -25,6 +34,8 @@ module Twirp
|
|
25
34
|
@auto_mount = false
|
26
35
|
@endpoint = "/twirp"
|
27
36
|
@load_paths = ["lib"]
|
37
|
+
@logger = Logger
|
38
|
+
@verbose_logging = false
|
28
39
|
@middleware = []
|
29
40
|
@service_hooks = {}
|
30
41
|
end
|
data/lib/twirp/rails/engine.rb
CHANGED
@@ -26,8 +26,15 @@ module Twirp
|
|
26
26
|
app.config.twirp.send(key)
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
# Set up logging
|
30
|
+
middleware.use app.config.twirp.logger, ::Rails.logger
|
31
|
+
app.config.twirp.middleware.each do |user_middleware|
|
32
|
+
middleware.use user_middleware
|
33
|
+
end
|
34
|
+
|
35
|
+
# Load all Twirp files
|
36
|
+
app.config.twirp.load_paths.each do |directory|
|
37
|
+
::Rails.root.glob("#{directory}/**/*_twirp.rb").sort.each { |file| require file }
|
31
38
|
end
|
32
39
|
end
|
33
40
|
end
|
@@ -35,17 +42,29 @@ module Twirp
|
|
35
42
|
class << self
|
36
43
|
def services
|
37
44
|
if @services.nil?
|
38
|
-
::Rails.application.config.twirp.load_paths.each do |directory|
|
39
|
-
::Rails.root.glob("#{directory}/**/*_twirp.rb").sort.each { |file| require file }
|
40
|
-
end
|
41
|
-
|
42
45
|
@services = Twirp::Service.subclasses.map(&:new)
|
43
46
|
|
44
47
|
# Install hooks that may be defined in the config
|
45
48
|
@services.each do |service|
|
49
|
+
# Add user-defined hooks
|
46
50
|
::Rails.application.config.twirp.service_hooks.each do |hook_name, hook|
|
47
51
|
service.send(hook_name, &hook)
|
48
52
|
end
|
53
|
+
|
54
|
+
# Add our own logging hooks
|
55
|
+
service.on_success do |env|
|
56
|
+
if ::Rails.application.config.twirp.verbose_logging
|
57
|
+
::Rails.logger.debug { "Twirp Response: #{env[:output].inspect}" }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
service.on_error do |error, _env|
|
62
|
+
::Rails.logger.debug { "Twirp Response: #{error.inspect}" }
|
63
|
+
end
|
64
|
+
|
65
|
+
service.exception_raised do |exception, _env|
|
66
|
+
::Rails.logger.error { "Twirp Exception (#{exception.class}: #{exception.message})\n#{exception.backtrace.join("\n")}" }
|
67
|
+
end
|
49
68
|
end
|
50
69
|
end
|
51
70
|
|
@@ -54,11 +73,3 @@ module Twirp
|
|
54
73
|
end
|
55
74
|
end
|
56
75
|
end
|
57
|
-
|
58
|
-
class Twirp::Service
|
59
|
-
# Override inspect to show all available RPCs
|
60
|
-
# This is used when displaying routes.
|
61
|
-
def inspect
|
62
|
-
self.class.rpcs.map { |rpc| "#{self.class.name.demodulize.underscore}_handler##{rpc[1][:ruby_method]}" }.join("\n")
|
63
|
-
end
|
64
|
-
end
|
data/lib/twirp/rails/handler.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Rack::CommonLogger is nice but we can do better.
|
4
|
+
# Rails doesn't use it, but we need to log Twirp requests.
|
5
|
+
# Here's an example from Rack::CommonLogger:
|
6
|
+
# 127.0.0.1 - - [12/Jan/2025:17:09:49 -0500] "POST /twirp/twirp.example.haberdasher.Haberdasher/MakeHat HTTP/1.0" 200 - 439.0060
|
7
|
+
#
|
8
|
+
# Rails gives us this:
|
9
|
+
# Started POST "/twirp/twirp.example.haberdasher.Haberdasher/MakeHat" for 127.0.0.1 at 2025-01-12 22:48:00 -0500
|
10
|
+
# but we also want to know the result of the Twirp call.
|
11
|
+
# Here's what this Logger adds:
|
12
|
+
# Twirp 200 in 2ms as application/protobuf
|
13
|
+
#
|
14
|
+
|
15
|
+
module Twirp
|
16
|
+
module Rails
|
17
|
+
class Logger < ::Rack::CommonLogger
|
18
|
+
private
|
19
|
+
|
20
|
+
def log(env, status, response_headers, began_at)
|
21
|
+
content_type = response_headers["content-type"].presence
|
22
|
+
content_encoding = response_headers["content-encoding"].presence
|
23
|
+
@logger.info { "Twirp #{status} in #{duration_in_ms(began_at)}ms#{" as #{content_type}" if content_type}#{" with content-encoding: #{content_encoding}" if content_encoding}" }
|
24
|
+
end
|
25
|
+
|
26
|
+
def duration_in_ms(time)
|
27
|
+
((::Rack::Utils.clock_time - time) * 1000).to_i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/twirp/rails/version.rb
CHANGED
data/lib/twirp/rails.rb
CHANGED
@@ -1,31 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "twirp"
|
4
|
+
require "active_support/notifications"
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
require "zeitwerk"
|
7
|
+
loader = Zeitwerk::Loader.for_gem_extension(Twirp)
|
8
|
+
loader.ignore("#{__dir__}/on/rails.rb")
|
9
|
+
loader.setup
|
10
|
+
|
11
|
+
module Twirp::Rails
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
loader.eager_load
|
15
|
+
|
16
|
+
Twirp::Service.class_eval do
|
17
|
+
# Override initialize to make handler argument optional.
|
18
|
+
# When left nil, we will use our dispatcher.
|
19
|
+
alias_method :original_initialize, :initialize
|
20
|
+
def initialize(handler = nil)
|
21
|
+
handler ||= Twirp::Rails::Dispatcher.new(self.class)
|
22
|
+
original_initialize(handler)
|
23
|
+
end
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
alias_method :original_initialize, :initialize
|
26
|
-
def initialize(handler = nil)
|
27
|
-
handler ||= Twirp::Rails::Dispatcher.new(self.class)
|
28
|
-
original_initialize(handler)
|
29
|
-
end
|
25
|
+
# Override inspect to show all available RPCs
|
26
|
+
# This is used when displaying routes.
|
27
|
+
def inspect
|
28
|
+
self.class.rpcs.map { |rpc| "#{self.class.name.demodulize.underscore}_handler##{rpc[1][:ruby_method]}" }.join("\n")
|
30
29
|
end
|
31
30
|
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twirp-on-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Morrison
|
8
8
|
- Darron Schall
|
9
|
-
autorequire:
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-01-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rails
|
@@ -61,7 +60,9 @@ files:
|
|
61
60
|
- lib/twirp/rails/configuration.rb
|
62
61
|
- lib/twirp/rails/dispatcher.rb
|
63
62
|
- lib/twirp/rails/engine.rb
|
63
|
+
- lib/twirp/rails/error.rb
|
64
64
|
- lib/twirp/rails/handler.rb
|
65
|
+
- lib/twirp/rails/logger.rb
|
65
66
|
- lib/twirp/rails/rack/conditional_post.rb
|
66
67
|
- lib/twirp/rails/rescuable.rb
|
67
68
|
- lib/twirp/rails/version.rb
|
@@ -74,7 +75,6 @@ metadata:
|
|
74
75
|
homepage_uri: https://github.com/collectiveidea/twirp-rails
|
75
76
|
source_code_uri: https://github.com/collectiveidea/twirp-rails
|
76
77
|
changelog_uri: https://github.com/collectiveidea/twirp-rails/blob/main/CHANGELOG.md
|
77
|
-
post_install_message:
|
78
78
|
rdoc_options: []
|
79
79
|
require_paths:
|
80
80
|
- lib
|
@@ -89,8 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
91
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
93
|
-
signing_key:
|
92
|
+
rubygems_version: 3.6.2
|
94
93
|
specification_version: 4
|
95
94
|
summary: Use Twirp RPC with Rails
|
96
95
|
test_files: []
|