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.
@@ -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
@@ -0,0 +1,3 @@
1
+ module ActiveRpc
2
+ VERSION = "1.0.1"
3
+ 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: []