the-active-rpc 1.0.1
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 +82 -0
- data/LICENSE +21 -0
- data/README.md +59 -0
- data/Rakefile +8 -0
- data/lib/active_rpc/client_config.rb +30 -0
- data/lib/active_rpc/client_factory.rb +61 -0
- data/lib/active_rpc/configuration.rb +50 -0
- data/lib/active_rpc/model_extensions/attribute_dsl.rb +31 -0
- data/lib/active_rpc/model_extensions.rb +1456 -0
- data/lib/active_rpc/rpc/base_controller.rb +63 -0
- data/lib/active_rpc/rpc/concerns/includable.rb +68 -0
- data/lib/active_rpc/rpc/concerns/paginatable.rb +155 -0
- data/lib/active_rpc/rpc/concerns/query_builder.rb +178 -0
- data/lib/active_rpc/rpc/concerns/ransackable.rb +113 -0
- data/lib/active_rpc/rpc/concerns/request_processor.rb +191 -0
- data/lib/active_rpc/rpc/concerns/resource_controller.rb +281 -0
- data/lib/active_rpc/rpc/concerns/scopable.rb +92 -0
- data/lib/active_rpc/rpc/concerns/serializable.rb +30 -0
- data/lib/active_rpc/rpc/concerns/sortable.rb +71 -0
- data/lib/active_rpc/rpc/configuration.rb +7 -0
- data/lib/active_rpc/rpc/interceptors/locale_interceptor.rb +38 -0
- data/lib/active_rpc/rpc.rb +18 -0
- data/lib/active_rpc/version.rb +3 -0
- data/lib/active_rpc.rb +15 -0
- data/lib/generators/active_rpc/client_setup/client_setup_generator.rb +57 -0
- data/lib/generators/active_rpc/controller/gruf_controller_generator.rb +60 -0
- data/lib/generators/active_rpc/server_setup/server_setup_generator.rb +11 -0
- data/lib/the-active-rpc.rb +1 -0
- metadata +196 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRpc
|
|
4
|
+
module Rpc
|
|
5
|
+
module Interceptors
|
|
6
|
+
# Locale interceptor that automatically sets I18n.locale from gRPC metadata
|
|
7
|
+
# This runs before every gRPC request, ensuring proper locale context
|
|
8
|
+
class LocaleInterceptor < ::Gruf::Interceptors::ServerInterceptor
|
|
9
|
+
def call(&block)
|
|
10
|
+
set_locale_from_metadata
|
|
11
|
+
yield
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
# Set I18n.locale from gRPC metadata: prefer explicit 'locale', then 'accept-language'
|
|
17
|
+
def set_locale_from_metadata
|
|
18
|
+
return unless request&.active_call&.metadata
|
|
19
|
+
|
|
20
|
+
md = request.active_call.metadata
|
|
21
|
+
return if md.nil? || md.empty?
|
|
22
|
+
|
|
23
|
+
available = I18n.available_locales.map(&:to_s) if defined?(I18n)
|
|
24
|
+
return unless available
|
|
25
|
+
|
|
26
|
+
locale = md['locale'] || md['accept-language']
|
|
27
|
+
return if locale.nil? || locale.empty?
|
|
28
|
+
|
|
29
|
+
primary = locale.to_s.split(',').first.to_s.split('-').first
|
|
30
|
+
if available.include?(primary)
|
|
31
|
+
I18n.locale = primary.to_sym
|
|
32
|
+
Rails.logger.debug "[LOCALE INTERCEPTOR] Set I18n.locale to: #{I18n.locale}" if defined?(Rails)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative 'rpc/configuration'
|
|
2
|
+
require_relative 'rpc/concerns/ransackable'
|
|
3
|
+
require_relative 'rpc/concerns/scopable'
|
|
4
|
+
require_relative 'rpc/concerns/includable'
|
|
5
|
+
require_relative 'rpc/concerns/paginatable'
|
|
6
|
+
require_relative 'rpc/concerns/sortable'
|
|
7
|
+
require_relative 'rpc/concerns/request_processor'
|
|
8
|
+
require_relative 'rpc/concerns/query_builder'
|
|
9
|
+
require_relative 'rpc/concerns/resource_controller'
|
|
10
|
+
require_relative 'rpc/concerns/serializable'
|
|
11
|
+
require_relative 'rpc/interceptors/locale_interceptor'
|
|
12
|
+
require_relative 'rpc/base_controller'
|
|
13
|
+
|
|
14
|
+
module ActiveRpc
|
|
15
|
+
module Rpc
|
|
16
|
+
# Namespace for gRPC server-side controller functionality
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/active_rpc.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'gruf'
|
|
2
|
+
require 'active_support'
|
|
3
|
+
|
|
4
|
+
require_relative 'active_rpc/version'
|
|
5
|
+
require_relative 'active_rpc/configuration'
|
|
6
|
+
require_relative 'active_rpc/client_factory'
|
|
7
|
+
require_relative 'active_rpc/client_config'
|
|
8
|
+
require_relative 'active_rpc/model_extensions'
|
|
9
|
+
require_relative 'active_rpc/rpc'
|
|
10
|
+
|
|
11
|
+
module ActiveRpc
|
|
12
|
+
extend ActiveSupport::Autoload
|
|
13
|
+
|
|
14
|
+
autoload :Configuration, 'active_rpc/configuration'
|
|
15
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/base"
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
require "yaml"
|
|
5
|
+
|
|
6
|
+
module ActiveRpc
|
|
7
|
+
module Generators
|
|
8
|
+
class ClientSetupGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path("templates", __dir__ || File.dirname(__FILE__))
|
|
10
|
+
|
|
11
|
+
def generate_client_config
|
|
12
|
+
grpc_config_path = "config/grpc_clients.yml"
|
|
13
|
+
services = extract_services_from_protos
|
|
14
|
+
|
|
15
|
+
if services.empty?
|
|
16
|
+
say_status("error", "No gRPC services found in the proto files.", :red)
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
template("configs.yml.erb", grpc_config_path, services: services)
|
|
21
|
+
say_status("success", "Generated gRPC client config at #{grpc_config_path}", :green)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def create_initializer
|
|
25
|
+
initializer_path = "config/initializers/active_rpc_client.rb"
|
|
26
|
+
template "initializer.rb.erb", initializer_path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def extract_services_from_protos
|
|
32
|
+
gem_path = Gem::Specification.find_by_name("active_rpc").gem_dir
|
|
33
|
+
proto_files = Dir.glob(File.join(gem_path, "protos/**/*.proto"))
|
|
34
|
+
|
|
35
|
+
services = {}
|
|
36
|
+
proto_files.each do |proto_file|
|
|
37
|
+
content = File.read(proto_file)
|
|
38
|
+
package_name = content[/option ruby_package = "(.*?)";/, 1]
|
|
39
|
+
service_names = content.scan(/service (\w+) \{/).flatten
|
|
40
|
+
|
|
41
|
+
next unless package_name && service_names.any?
|
|
42
|
+
|
|
43
|
+
services[package_name] ||= {
|
|
44
|
+
"grpc_host" => "#{package_name.dasherize}-app-grpc".downcase,
|
|
45
|
+
"grpc_port" => 10541,
|
|
46
|
+
"use_ssl" => false,
|
|
47
|
+
"services" => []
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
services[package_name]["services"].concat(service_names)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
services
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/base"
|
|
3
|
+
require 'active_support/inflector'
|
|
4
|
+
|
|
5
|
+
module ActiveRpc
|
|
6
|
+
module Generators
|
|
7
|
+
class GrufControllerGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("templates", __dir__ || File.dirname(__FILE__))
|
|
9
|
+
argument :proto_file, type: :string, desc: "Path to the .proto file inside the gem"
|
|
10
|
+
|
|
11
|
+
def generate_controller
|
|
12
|
+
parsed_data = parse_proto_file(proto_file)
|
|
13
|
+
return unless parsed_data
|
|
14
|
+
|
|
15
|
+
package_name = parsed_data[:package_name]
|
|
16
|
+
service_name = parsed_data[:service_name]
|
|
17
|
+
rpc_methods = parsed_data[:rpc_methods]
|
|
18
|
+
|
|
19
|
+
controller_name = "#{service_name}Controller"
|
|
20
|
+
|
|
21
|
+
destination_path = "app/rpc/#{package_name.underscore}/#{controller_name.underscore}.rb"
|
|
22
|
+
|
|
23
|
+
template(
|
|
24
|
+
"gruf_controller.rb.erb",
|
|
25
|
+
destination_path,
|
|
26
|
+
package_name: package_name,
|
|
27
|
+
service_name: service_name,
|
|
28
|
+
controller_name: controller_name,
|
|
29
|
+
rpc_methods: rpc_methods
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def parse_proto_file(proto_relative_path)
|
|
36
|
+
# 🔹 Locate `.proto` file inside the installed gem
|
|
37
|
+
gem_path = Gem::Specification.find_by_name("active_rpc").gem_dir
|
|
38
|
+
proto_full_path = File.join(gem_path, "protos", proto_relative_path)
|
|
39
|
+
|
|
40
|
+
unless File.exist?(proto_full_path)
|
|
41
|
+
say_status("error", "Could not find #{proto_full_path}", :red)
|
|
42
|
+
return nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
content = File.read(proto_full_path)
|
|
46
|
+
|
|
47
|
+
package_name = content[/option ruby_package = "(.*?)";/, 1]
|
|
48
|
+
service_name = content[/service (\w+) \{/, 1]
|
|
49
|
+
|
|
50
|
+
return nil unless package_name && service_name
|
|
51
|
+
|
|
52
|
+
rpc_methods = content.scan(/rpc (\w+) \((\w+)\) returns \((\w+)\);/).map do |match|
|
|
53
|
+
{ name: match[0], request: match[1], response: match[2] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
{ package_name: package_name, service_name: service_name, rpc_methods: rpc_methods }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module ActiveRpc
|
|
2
|
+
module Generators
|
|
3
|
+
class ServerSetupGenerator < Rails::Generators::Base
|
|
4
|
+
source_root File.expand_path("templates", __dir__ || File.dirname(__FILE__))
|
|
5
|
+
|
|
6
|
+
def copy_initializer_file
|
|
7
|
+
template "initializer.rb.erb", "config/initializers/active_rpc_server.rb"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'active_rpc'
|
metadata
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: the-active-rpc
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Khaled AbuShqear
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '6.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '6.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: gruf
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.21'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.21'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: dry-configurable
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.3'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.3'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: ostruct
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: pagy
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: activerecord
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '6.0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '6.0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rspec
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: sqlite3
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: rails
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
131
|
+
type: :development
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0'
|
|
138
|
+
description: Treat remote gRPC services like local ActiveRecord associations. Supports
|
|
139
|
+
bulk loading, dirty tracking, cross-service filtering, and bidirectional create/update
|
|
140
|
+
propagation.
|
|
141
|
+
email:
|
|
142
|
+
- qmax93@gmail.com
|
|
143
|
+
executables: []
|
|
144
|
+
extensions: []
|
|
145
|
+
extra_rdoc_files: []
|
|
146
|
+
files:
|
|
147
|
+
- CHANGELOG.md
|
|
148
|
+
- LICENSE
|
|
149
|
+
- README.md
|
|
150
|
+
- Rakefile
|
|
151
|
+
- lib/active_rpc.rb
|
|
152
|
+
- lib/active_rpc/client_config.rb
|
|
153
|
+
- lib/active_rpc/client_factory.rb
|
|
154
|
+
- lib/active_rpc/configuration.rb
|
|
155
|
+
- lib/active_rpc/model_extensions.rb
|
|
156
|
+
- lib/active_rpc/model_extensions/attribute_dsl.rb
|
|
157
|
+
- lib/active_rpc/rpc.rb
|
|
158
|
+
- lib/active_rpc/rpc/base_controller.rb
|
|
159
|
+
- lib/active_rpc/rpc/concerns/includable.rb
|
|
160
|
+
- lib/active_rpc/rpc/concerns/paginatable.rb
|
|
161
|
+
- lib/active_rpc/rpc/concerns/query_builder.rb
|
|
162
|
+
- lib/active_rpc/rpc/concerns/ransackable.rb
|
|
163
|
+
- lib/active_rpc/rpc/concerns/request_processor.rb
|
|
164
|
+
- lib/active_rpc/rpc/concerns/resource_controller.rb
|
|
165
|
+
- lib/active_rpc/rpc/concerns/scopable.rb
|
|
166
|
+
- lib/active_rpc/rpc/concerns/serializable.rb
|
|
167
|
+
- lib/active_rpc/rpc/concerns/sortable.rb
|
|
168
|
+
- lib/active_rpc/rpc/configuration.rb
|
|
169
|
+
- lib/active_rpc/rpc/interceptors/locale_interceptor.rb
|
|
170
|
+
- lib/active_rpc/version.rb
|
|
171
|
+
- lib/generators/active_rpc/client_setup/client_setup_generator.rb
|
|
172
|
+
- lib/generators/active_rpc/controller/gruf_controller_generator.rb
|
|
173
|
+
- lib/generators/active_rpc/server_setup/server_setup_generator.rb
|
|
174
|
+
- lib/the-active-rpc.rb
|
|
175
|
+
homepage: https://github.com/athar-association/active_rpc
|
|
176
|
+
licenses:
|
|
177
|
+
- MIT
|
|
178
|
+
metadata: {}
|
|
179
|
+
rdoc_options: []
|
|
180
|
+
require_paths:
|
|
181
|
+
- lib
|
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - ">="
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: 3.3.0
|
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
|
+
requirements:
|
|
189
|
+
- - ">="
|
|
190
|
+
- !ruby/object:Gem::Version
|
|
191
|
+
version: '0'
|
|
192
|
+
requirements: []
|
|
193
|
+
rubygems_version: 3.6.9
|
|
194
|
+
specification_version: 4
|
|
195
|
+
summary: ActiveRecord-gRPC bridge for distributed Rails applications
|
|
196
|
+
test_files: []
|