tonic-rails 0.1.0-aarch64-linux-gnu
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 +7 -0
- data/CHANGELOG.md +52 -0
- data/LICENSE +21 -0
- data/README.md +391 -0
- data/lib/tonic/rails/3.3/tonic_rails_native.so +0 -0
- data/lib/tonic/rails/3.4/tonic_rails_native.so +0 -0
- data/lib/tonic/rails/4.0/tonic_rails_native.so +0 -0
- data/lib/tonic/rails/base.rb +215 -0
- data/lib/tonic/rails/configuration.rb +149 -0
- data/lib/tonic/rails/railtie.rb +56 -0
- data/lib/tonic/rails/reflection.rb +50 -0
- data/lib/tonic/rails/router.rb +71 -0
- data/lib/tonic/rails/rpc_error.rb +65 -0
- data/lib/tonic/rails/server.rb +224 -0
- data/lib/tonic/rails/tasks/tonic-rails.rake +36 -0
- data/lib/tonic/rails/testing.rb +85 -0
- data/lib/tonic/rails/version.rb +7 -0
- data/lib/tonic-rails.rb +91 -0
- metadata +107 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tonic
|
|
4
|
+
module Rails
|
|
5
|
+
# Call handlers in-process, without a network or the native extension.
|
|
6
|
+
# Requests and responses go through real protobuf encoding, so tests
|
|
7
|
+
# exercise the same conversion the server does.
|
|
8
|
+
#
|
|
9
|
+
# require "tonic/rails/testing"
|
|
10
|
+
#
|
|
11
|
+
# response = Tonic::Rails::Testing.call(ProductService, :GetProduct, { id: 1 })
|
|
12
|
+
# response.title # => "Widget"
|
|
13
|
+
#
|
|
14
|
+
# expect { Tonic::Rails::Testing.call(ProductService, :GetProduct, { id: 0 }) }
|
|
15
|
+
# .to raise_error(Tonic::Rails::RpcError) { |e| expect(e.code_name).to eq(:not_found) }
|
|
16
|
+
module Testing
|
|
17
|
+
# Request side of a call: yields pre-encoded messages.
|
|
18
|
+
class Reader
|
|
19
|
+
def initialize(messages, error: nil)
|
|
20
|
+
@messages = messages.dup
|
|
21
|
+
@error = error
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def next
|
|
25
|
+
@messages.shift
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_reader :error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Response side of a call: collects encoded messages.
|
|
32
|
+
class Sender
|
|
33
|
+
attr_reader :messages
|
|
34
|
+
|
|
35
|
+
def initialize
|
|
36
|
+
@messages = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def push(bytes)
|
|
40
|
+
@messages << bytes
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module_function
|
|
45
|
+
|
|
46
|
+
# @param service_class [Class] handler class
|
|
47
|
+
# @param rpc_name [Symbol, String] RPC name as in the .proto
|
|
48
|
+
# @param request [Google::Protobuf::AbstractMessage, Hash, Array] the
|
|
49
|
+
# request; an Array of them for client- and bidi-streaming RPCs
|
|
50
|
+
# @param metadata [Hash{String=>String}]
|
|
51
|
+
# @param timeout_ms [Integer, nil] simulated client deadline
|
|
52
|
+
# @return [Google::Protobuf::AbstractMessage, Array] the response, or
|
|
53
|
+
# an Array of responses for server- and bidi-streaming RPCs
|
|
54
|
+
# @raise [RpcError] when the handler ends the call with a status
|
|
55
|
+
def call(service_class, rpc_name, request, metadata: {}, timeout_ms: nil)
|
|
56
|
+
spec = service_class.grpc_rpcs.fetch(rpc_name.to_s) do
|
|
57
|
+
raise ArgumentError, "#{service_class} has no RPC #{rpc_name}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
requests = spec[:request_stream] ? Array(request) : [request]
|
|
61
|
+
reader = Reader.new(requests.map { |r| encode(spec[:request], r) })
|
|
62
|
+
sender = Sender.new
|
|
63
|
+
|
|
64
|
+
result = service_class.new.call_rpc(
|
|
65
|
+
rpc_name.to_s,
|
|
66
|
+
metadata: metadata.transform_keys(&:to_s),
|
|
67
|
+
reader: reader,
|
|
68
|
+
sender: sender,
|
|
69
|
+
timeout_ms: timeout_ms,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if spec[:response_stream]
|
|
73
|
+
sender.messages.map { |bytes| spec[:response].decode(bytes) }
|
|
74
|
+
else
|
|
75
|
+
spec[:response].decode(result)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def encode(klass, message)
|
|
80
|
+
message = klass.new(message) if message.is_a?(Hash)
|
|
81
|
+
klass.encode(message)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/tonic-rails.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "google/protobuf"
|
|
4
|
+
|
|
5
|
+
module Tonic
|
|
6
|
+
module Rails
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
class NotConfiguredError < Error; end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require "tonic/rails/version"
|
|
13
|
+
require "tonic/rails/rpc_error"
|
|
14
|
+
require "tonic/rails/configuration"
|
|
15
|
+
require "tonic/rails/router"
|
|
16
|
+
require "tonic/rails/base"
|
|
17
|
+
require "tonic/rails/reflection"
|
|
18
|
+
require "tonic/rails/server"
|
|
19
|
+
|
|
20
|
+
module Tonic
|
|
21
|
+
module Rails
|
|
22
|
+
@configuration = Configuration.new
|
|
23
|
+
@shutting_down = false
|
|
24
|
+
@native_load_error = nil
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
attr_reader :configuration
|
|
28
|
+
|
|
29
|
+
def configure
|
|
30
|
+
yield @configuration
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The process-wide server used by the Railtie and rake tasks.
|
|
34
|
+
def server
|
|
35
|
+
@server ||= Server.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# True once shutdown has begun. Long-running handlers (especially
|
|
39
|
+
# streams) should check this and finish early.
|
|
40
|
+
def cancelled?
|
|
41
|
+
@shutting_down
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @api private
|
|
45
|
+
def _set_shutting_down(value)
|
|
46
|
+
@shutting_down = value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @api private
|
|
50
|
+
# Log an unexpected exception (and hand it to the Rails error
|
|
51
|
+
# reporter, if present) without exposing it to the client.
|
|
52
|
+
def log_exception(error, context)
|
|
53
|
+
configuration.logger&.error(
|
|
54
|
+
"tonic-rails: #{context}: #{error.class}: #{error.message}\n" \
|
|
55
|
+
"#{Array(error.backtrace).first(20).join("\n")}",
|
|
56
|
+
)
|
|
57
|
+
if defined?(::Rails.error) && ::Rails.respond_to?(:error)
|
|
58
|
+
::Rails.error.report(error, handled: true, source: "tonic-rails", context: { rpc: context })
|
|
59
|
+
end
|
|
60
|
+
rescue StandardError
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @api private
|
|
65
|
+
def native_extension!
|
|
66
|
+
return if defined?(::TonicRails::Native::Server)
|
|
67
|
+
|
|
68
|
+
raise Error, "tonic-rails native extension is not available " \
|
|
69
|
+
"(#{@native_load_error&.message || 'unknown error'}). " \
|
|
70
|
+
"Reinstall the gem, or run `bundle exec rake compile` in a checkout."
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @api private
|
|
74
|
+
def load_native_extension
|
|
75
|
+
# Precompiled platform gems ship one binary per Ruby minor version.
|
|
76
|
+
ruby_version = RUBY_VERSION[/\d+\.\d+/]
|
|
77
|
+
require "tonic/rails/#{ruby_version}/tonic_rails_native"
|
|
78
|
+
rescue LoadError
|
|
79
|
+
begin
|
|
80
|
+
require "tonic/rails/tonic_rails_native"
|
|
81
|
+
rescue LoadError => e
|
|
82
|
+
@native_load_error = e
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
load_native_extension
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
require "tonic/rails/railtie" if defined?(Rails::Railtie)
|
metadata
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tonic-rails
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: aarch64-linux-gnu
|
|
6
|
+
authors:
|
|
7
|
+
- Matt Tanous
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-10-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '7.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: google-protobuf
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '4.27'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '4.27'
|
|
41
|
+
description: |
|
|
42
|
+
Tonic::Rails serves gRPC from Rails applications. The transport layer
|
|
43
|
+
(HTTP/2 framing, connection management, TLS, health checks, reflection)
|
|
44
|
+
is handled by tonic in Rust and exposed to Ruby through a native
|
|
45
|
+
extension built with Magnus. Protobuf (de)serialization and business
|
|
46
|
+
logic remain in Ruby, giving you Rails-grade handlers, routing,
|
|
47
|
+
interceptors, and the Rails executor around every RPC.
|
|
48
|
+
email:
|
|
49
|
+
- matt.tanous@hey.com
|
|
50
|
+
executables: []
|
|
51
|
+
extensions: []
|
|
52
|
+
extra_rdoc_files: []
|
|
53
|
+
files:
|
|
54
|
+
- CHANGELOG.md
|
|
55
|
+
- LICENSE
|
|
56
|
+
- README.md
|
|
57
|
+
- lib/tonic-rails.rb
|
|
58
|
+
- lib/tonic/rails/3.3/tonic_rails_native.so
|
|
59
|
+
- lib/tonic/rails/3.4/tonic_rails_native.so
|
|
60
|
+
- lib/tonic/rails/4.0/tonic_rails_native.so
|
|
61
|
+
- lib/tonic/rails/base.rb
|
|
62
|
+
- lib/tonic/rails/configuration.rb
|
|
63
|
+
- lib/tonic/rails/railtie.rb
|
|
64
|
+
- lib/tonic/rails/reflection.rb
|
|
65
|
+
- lib/tonic/rails/router.rb
|
|
66
|
+
- lib/tonic/rails/rpc_error.rb
|
|
67
|
+
- lib/tonic/rails/server.rb
|
|
68
|
+
- lib/tonic/rails/tasks/tonic-rails.rake
|
|
69
|
+
- lib/tonic/rails/testing.rb
|
|
70
|
+
- lib/tonic/rails/version.rb
|
|
71
|
+
homepage: https://github.com/CodingAnarchy/tonic-rails
|
|
72
|
+
licenses:
|
|
73
|
+
- MIT
|
|
74
|
+
metadata:
|
|
75
|
+
allowed_push_host: https://rubygems.org
|
|
76
|
+
homepage_uri: https://github.com/CodingAnarchy/tonic-rails
|
|
77
|
+
source_code_uri: https://github.com/CodingAnarchy/tonic-rails
|
|
78
|
+
bug_tracker_uri: https://github.com/CodingAnarchy/tonic-rails/issues
|
|
79
|
+
changelog_uri: https://github.com/CodingAnarchy/tonic-rails/blob/main/CHANGELOG.md
|
|
80
|
+
rubygems_mfa_required: 'true'
|
|
81
|
+
post_install_message:
|
|
82
|
+
rdoc_options: []
|
|
83
|
+
require_paths:
|
|
84
|
+
- lib
|
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.3'
|
|
90
|
+
- - "<"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 4.1.dev
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: 3.3.11
|
|
98
|
+
- - ">="
|
|
99
|
+
- !ruby/object:Gem::Version
|
|
100
|
+
version: 3.3.22
|
|
101
|
+
requirements: []
|
|
102
|
+
rubygems_version: 3.5.23
|
|
103
|
+
signing_key:
|
|
104
|
+
specification_version: 4
|
|
105
|
+
summary: High-performance gRPC endpoints for Rails, powered by tonic via a Rust native
|
|
106
|
+
extension
|
|
107
|
+
test_files: []
|