inigorb 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8fd78ac0ebe0a29c918b14393b77a7f0e70fc2ac7784a1044ce1dc6aed24b3d1
4
+ data.tar.gz: d1456a17c854c33f1e503fcbf7f0dbcc777b3dbff66a71fee5bf0a185c78e3cc
5
+ SHA512:
6
+ metadata.gz: 2fc9a795e9d758776410c4636c8bb9f5e3727a57c748ab6d6106c84eb9fdf4f15af0b981b7560f7e6539bf3e5605f1455a02f681be804cd41a29eecd52bcac9f
7
+ data.tar.gz: e4cc38bf13719eaac2228980dd6ec029cf9f2c6b7e741ece04fc60fa65eefadf99f433225a749b02f1ceebedd77accc01283bdafc4a5af8e66216220d919ccee
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ <br />
2
+ <div align="center">
3
+ <img src="/assets/inigo.svg">
4
+ <img height="25" src="/assets/ruby.svg">
5
+
6
+ <p align="center">
7
+ GraphQL Middleware
8
+ <br />
9
+ <a href="https://docs.inigo.io"><strong>Explore the docs »</strong></a>
10
+ <br /> <br />
11
+ <a href="https://inigo.io">Homepage</a>
12
+ ·
13
+ <a href="https://github.com/inigolabs/inigo-ruby/tree/master/example-rails">View an example</a>
14
+ ·
15
+ <a href="https://github.com/inigolabs/inigo-ruby/issues">Report Bug</a>
16
+ </p>
17
+ </div>
18
+
19
+ ### Documentation
20
+
21
+ This package is the Inigo plugin for Ruby servers.
22
+
23
+ Documentation is available here: [docs.inigo.io](https://docs.inigo.io/docs/deployment)
24
+
25
+ ### Contributing
26
+
27
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
28
+
29
+ ### License
30
+ Distributed under the MIT License.
data/lib/ffimod.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'ffi'
2
+
3
+ module Inigo
4
+ extend FFI::Library
5
+
6
+ def self.get_arch(system_name)
7
+ machine = RbConfig::CONFIG['target_cpu'].downcase
8
+ if system_name == 'darwin'
9
+ return 'amd64' if machine == 'x86_64'
10
+ return 'arm64' if machine == 'arm64'
11
+ end
12
+
13
+ if system_name == 'linux'
14
+ if machine == 'x86_64' && ['64bit', 'universal'].include?(RUBY_PLATFORM.match(/(\d+)/)[0])
15
+ return 'amd64'
16
+ elsif machine == 'aarch64'
17
+ return 'arm64'
18
+ elsif machine == 'x86_64' && RUBY_PLATFORM.match?(/(i\d86|x\d86)/)
19
+ return '386'
20
+ elsif machine.start_with?('arm') # armv7l
21
+ return 'arm'
22
+ end
23
+ end
24
+
25
+ if system_name == 'windows'
26
+ return 'amd64' if ['x86_64', 'universal'].include?(RbConfig::CONFIG['host_cpu'])
27
+ end
28
+
29
+ machine
30
+ end
31
+
32
+ def self.get_ext(system_name)
33
+ return '.dll' if system_name == 'windows'
34
+ return '.dylib' if system_name == 'darwin'
35
+
36
+ '.so'
37
+ end
38
+
39
+ system_name = RbConfig::CONFIG['host_os']
40
+
41
+ supported_systems = /(linux|darwin|mingw|mswin|cygwin)/
42
+
43
+ unless supported_systems.match?(system_name)
44
+ raise RuntimeError, "Only Windows, macOS (darwin), and Linux systems are supported. RUBY_PLATFORM: #{RUBY_PLATFORM}, RUBY_ENGINE: #{RUBY_ENGINE}, HOST_OS: #{system_name}"
45
+ end
46
+
47
+ system_name = 'windows' if system_name =~ /(mingw|mswin|cygwin)/
48
+ system_name = 'darwin' if system_name =~ /darwin/i
49
+ system_name = 'linux' if system_name =~ /linux/i
50
+
51
+ filename = "inigo-#{system_name}-#{get_arch(system_name)}#{get_ext(system_name)}"
52
+
53
+ begin
54
+ ffi_lib File.join(File.dirname(__FILE__), filename)
55
+
56
+ class Config < FFI::Struct
57
+ layout :debug, :bool,
58
+ :ingest, :pointer,
59
+ :service, :pointer,
60
+ :token, :pointer,
61
+ :schema, :pointer,
62
+ :introspection, :pointer
63
+ end
64
+
65
+ attach_function :create, [:u_int64_t], :u_int64_t
66
+ attach_function :process_request, [
67
+ :u_int64_t, # instance
68
+ :pointer, :int, # header
69
+ :pointer, :int, # input
70
+ :pointer, :pointer, # output
71
+ :pointer, :pointer # status
72
+ ], :u_int64_t
73
+ attach_function :process_response, [
74
+ :u_int64_t, # instance
75
+ :u_int64_t, # request handler
76
+ :pointer, :int, # input
77
+ :pointer, :pointer # output
78
+ ], :void
79
+ attach_function :get_version, [], :string
80
+ attach_function :disposeHandle, [:u_int64_t], :void
81
+ attach_function :disposeMemory, [:pointer], :void
82
+ attach_function :check_lasterror, [], :string
83
+ rescue LoadError => e
84
+ raise ::RuntimeError, "Unable to open Inigo shared library.\n\nPlease get in touch with us for support:\nemail: support@inigo.io\nslack: https://slack.inigo.io\n\nPlease share the below info with us:\nerror: #{e.to_s}\nuname: #{RbConfig::CONFIG['host_os']}\narch: #{RbConfig::CONFIG['host_cpu']}"
85
+ end
86
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/lib/inigorb.rb ADDED
@@ -0,0 +1,204 @@
1
+ require 'json'
2
+ require 'ffi'
3
+ require_relative 'ffimod'
4
+ require_relative 'query'
5
+
6
+ module Inigo
7
+ class Middleware
8
+ @@instance = 0
9
+ @@initialized = false
10
+ @@path = ''
11
+ @@schema = ''
12
+
13
+ def self.instance
14
+ @@instance
15
+ end
16
+
17
+ def self.instance=(value)
18
+ @@instance = value
19
+ end
20
+
21
+ def self.initialized
22
+ @@initialized
23
+ end
24
+
25
+ def self.initialized=(value)
26
+ @@initialized = value
27
+ end
28
+
29
+ def self.path
30
+ @@path
31
+ end
32
+
33
+ def self.path=(value)
34
+ @@path = value
35
+ end
36
+
37
+ def self.schema
38
+ @@schema
39
+ end
40
+
41
+ def self.schema=(value)
42
+ @@schema = value
43
+ end
44
+
45
+ def initialize(app)
46
+ @app = app
47
+ end
48
+
49
+ def call(env)
50
+ # Ignore execution if Inigo is not initialized
51
+ if self.class.instance == 0
52
+ return @app.call(env)
53
+ end
54
+
55
+ request = Rack::Request.new(env)
56
+
57
+ # 'path' guard -> /graphql
58
+ if request.path != self.class.path
59
+ return @app.call(env)
60
+ end
61
+
62
+ # GraphiQL request
63
+ if request.get? && request.accept.include?('text/html')
64
+ return @app.call(env)
65
+ end
66
+
67
+ # Support only POST and GET requests
68
+ if !request.post? && !request.get?
69
+ return @app.call(env)
70
+ end
71
+
72
+ # Parse request
73
+ gReq = ''
74
+ if request.post?
75
+ # Read request from body
76
+ request.body.each { |chunk| gReq += chunk }
77
+ request.body.rewind
78
+ elsif request.get?
79
+ # Read request from query param
80
+ gReq = JSON.dump({ 'query' => request.params['query'] })
81
+ end
82
+
83
+ q = Query.new(self.class.instance, gReq)
84
+
85
+ # Inigo: process request
86
+ resp, req = q.process_request(headers(request))
87
+
88
+ # Introspection query
89
+ if resp.any?
90
+ return respond(resp)
91
+ end
92
+
93
+ # Modify query if required
94
+ if req.any?
95
+ if request.post?
96
+ body = JSON.parse(request.body.read)
97
+ body.merge!(
98
+ 'query' => req['query'],
99
+ 'operationName' => req['operationName'],
100
+ 'variables' => req['variables']
101
+ )
102
+ request.body = Rack::Utils.build_nested_query(body)
103
+ elsif request.get?
104
+ params = request.params
105
+ params['query'] = req['query']
106
+ request.update_param(params)
107
+ end
108
+ end
109
+
110
+ # Forward to request handler
111
+ response = @app.call(env)
112
+
113
+ # Inigo: process response
114
+ processed_response = q.process_response(response[2].body.to_s)
115
+ if processed_response
116
+ return respond(processed_response)
117
+ end
118
+
119
+ response
120
+ end
121
+
122
+ private
123
+
124
+ def self.initialize_middleware(schema = nil)
125
+ return if @@initialized
126
+
127
+ if schema
128
+ @@schema = schema
129
+ end
130
+ # get all the inigo settings from env
131
+ settings = ENV.select { |k, v| k.start_with?('INIGO') }
132
+
133
+ if settings.fetch("INIGO_ENABLE", "").to_s.downcase == "false"
134
+ @@initialized = true #not to get to this method ever again
135
+ puts 'Inigo is disabled. Skipping middleware.'
136
+ return
137
+ end
138
+
139
+ config = Inigo::Config.new
140
+
141
+ if settings.fetch("INIGO_DEBUG", "false").to_s.downcase == "true"
142
+ config[:debug] = true
143
+ else
144
+ config[:debug] = false
145
+ end
146
+
147
+ config[:token] = FFI::MemoryPointer.from_string(settings.fetch('INIGO_SERVICE_TOKEN', '').to_s.encode('UTF-8'))
148
+
149
+ schema = nil
150
+ if @@schema
151
+ schema = @@schema
152
+ elsif settings.fetch('INIGO_SCHEMA_PATH', '') != ''
153
+ path = settings.fetch('INIGO_SCHEMA_PATH')
154
+ if File.exist?(path)
155
+ schema = File.read(path)
156
+ end
157
+ end
158
+
159
+ config[:schema] = FFI::MemoryPointer.from_string(schema.to_s.encode('UTF-8')) if schema
160
+
161
+ @@path = settings.fetch('INIGO_PATH', '/query')
162
+
163
+ # Create Inigo instance
164
+ @@instance = Inigo.create(config.pointer.address)
165
+
166
+ error = Inigo.check_lasterror
167
+ if error.length != 0
168
+ puts "INIGO: #{error.read_string}"
169
+ end
170
+
171
+ if @@instance == 0
172
+ puts 'INIGO: error, instance cannot be created'
173
+ end
174
+
175
+ @@initialized = true
176
+ end
177
+
178
+ def headers(request)
179
+ headers = {}
180
+
181
+ request.env.each do |key, value|
182
+ if key.start_with?('HTTP_')
183
+ header_name = key[5..].split('_').map(&:capitalize).join('-')
184
+ headers[header_name] = value.split(',').map(&:strip)
185
+ elsif key == 'CONTENT_TYPE' || key == 'REMOTE_ADDR'
186
+ headers[key] = value.split(',').map(&:strip)
187
+ end
188
+ end
189
+
190
+ JSON.dump(headers)
191
+ end
192
+
193
+ def respond(data)
194
+ response = Rack::Response.new
195
+ response_hash = {}
196
+ response_hash['data'] = data['data'] if data['data']
197
+ response_hash['errors'] = data['errors'] if data['errors']
198
+ response_hash['extensions'] = data['extensions'] if data['extensions']
199
+ response.write(JSON.dump(response_hash))
200
+ response.finish
201
+ end
202
+
203
+ end
204
+ end
data/lib/query.rb ADDED
@@ -0,0 +1,80 @@
1
+ require 'json'
2
+ require_relative 'ffimod'
3
+
4
+ module Inigo
5
+ class Query
6
+ def initialize(instance, request)
7
+ @handle = 0
8
+ @instance = instance
9
+ @request = request
10
+ end
11
+
12
+ def process_request(headers)
13
+ resp_input = FFI::MemoryPointer.from_string(@request)
14
+
15
+ output_ptr = FFI::MemoryPointer.new(:pointer)
16
+ output_len = FFI::MemoryPointer.new(:int)
17
+
18
+ status_ptr = FFI::MemoryPointer.new(:pointer)
19
+ status_len = FFI::MemoryPointer.new(:int)
20
+
21
+ headers_ptr = FFI::MemoryPointer.from_string(headers.to_s)
22
+ headers_len = headers.to_s.length
23
+
24
+ @handle = Inigo.process_request(
25
+ @instance,
26
+ headers_ptr, headers_len,
27
+ resp_input, @request.length,
28
+ output_ptr, output_len,
29
+ status_ptr, status_len
30
+ )
31
+
32
+ resp_dict = {}
33
+ req_dict = {}
34
+
35
+ output_len_value = output_len.read_int
36
+ if output_len_value > 0
37
+ output_data = output_ptr.read_pointer.read_string(output_len_value)
38
+ resp_dict = JSON.parse(output_data)
39
+ end
40
+
41
+ status_len_value = status_len.read_int
42
+ if status_len_value > 0
43
+ status_data = status_ptr.read_pointer.read_string(status_len_value)
44
+ req_dict = JSON.parse(status_data)
45
+ end
46
+
47
+ Inigo.disposeMemory(output_ptr.read_pointer)
48
+ Inigo.disposeMemory(status_ptr.read_pointer)
49
+
50
+ [resp_dict, req_dict]
51
+ end
52
+
53
+ def process_response(resp_body)
54
+ return nil if @handle.zero?
55
+
56
+ output_ptr = FFI::MemoryPointer.new(:pointer)
57
+ output_len = FFI::MemoryPointer.new(:int)
58
+
59
+ Inigo.process_response(
60
+ @instance,
61
+ @handle,
62
+ FFI::MemoryPointer.from_string(resp_body), resp_body.length,
63
+ output_ptr, output_len
64
+ )
65
+
66
+ output_dict = {}
67
+
68
+ output_len_value = output_len.read_int
69
+ if output_len_value > 0
70
+ output_data = output_ptr.read_pointer.read_string(output_len_value)
71
+ output_dict = JSON.parse(output_data)
72
+ end
73
+
74
+ Inigo.disposeMemory(output_ptr.read_pointer)
75
+ Inigo.disposeHandle(@handle)
76
+
77
+ output_dict
78
+ end
79
+ end
80
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inigorb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Inigo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.7.1
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.7.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 2.7.1
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.7.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: ffi
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.15.5
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.15.5
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 1.15.5
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.15.5
53
+ description:
54
+ email: eitan@inigo.io
55
+ executables: []
56
+ extensions: []
57
+ extra_rdoc_files: []
58
+ files:
59
+ - README.md
60
+ - lib/ffimod.rb
61
+ - lib/inigo-darwin-amd64.dylib
62
+ - lib/inigo-darwin-arm64.dylib
63
+ - lib/inigo-linux-amd64.so
64
+ - lib/inigo-linux-arm64.so
65
+ - lib/inigo-windows-amd64.dll
66
+ - lib/inigo-windows-arm64.dll
67
+ - lib/inigorb.rb
68
+ - lib/query.rb
69
+ homepage: https://inigo.io
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ documentation_uri: https://docs.inigo.io
74
+ homepage_uri: https://inigo.io
75
+ source_code_uri: https://github.com/inigolabs/inigo-rb/blob/master
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 3.1.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.3.26
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Inigo GraphQL plugin for Ruby
95
+ test_files: []