rule_engine_client 0.1.14 → 0.1.16

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rule_engine_client.rb +205 -163
  3. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b1a8c9b6eb9a607d635b566a2af02cc2d030a6167fd62b4bb6f85c2ace1bbef
4
- data.tar.gz: dc62fc28e9c85659cbb069484f129fdc2577bd285e06b99c6ee23378215e5429
3
+ metadata.gz: 6698e5437993a11e71039e2c8b98050d8cd3784e2efcc1cacb72220cddf4528d
4
+ data.tar.gz: 7d5aa87bd97116c920811330a216140dee70efc3e3dfeb73b36bd0ba4efcc79a
5
5
  SHA512:
6
- metadata.gz: 5630592647ac4066156880b42a6ebe8b75f938a1fdbd02a6fed0f1f84db21363148600e4816ee7736b8ccf8ec1bca561fb268b4a2511b1706ef5f93ad492fa3d
7
- data.tar.gz: 63aabb4250fb31f68419211894eaab84f0fc0c28941f66839131c69b4cd95abc4d0fd8550074f3b47b6c0c0d22cd4e1bc10066eced3bca081699fd4c140d5bdc
6
+ metadata.gz: 0a7bfcde500e54a62845534f633841fefca67f66b71ee284a8af6e9d6bba1f14d46f710674dee502a2bc8d999ec0173db832c92abcc311ed7f8ac2e7db1ddb98
7
+ data.tar.gz: 99642690f3a3885c1401d3bdf3af99092c03af8d84c899dbddbd388752babbbc3e325bafb1861fe2a41a8c59804c0eada86a070339743a18ac77632a61bfebc6
@@ -1,163 +1,205 @@
1
- require 'net/http'
2
- require 'json'
3
- require 'logger'
4
- require 'timeout'
5
- require 'digest/md5'
6
-
7
- # rule engine client class
8
- class RuleEngineClient
9
- def initialize(server = 'http://localhost:8088', request_timeout_in_s = 5, verbose = false)
10
- @server = server
11
- @verbose = verbose
12
- @logger = Logger.new($stdout)
13
- @request_timeout_in_s = request_timeout_in_s
14
- @user_name = 'areej'
15
- @password = '123456'
16
- log("'#{server}' client is initialized")
17
- end
18
-
19
- def evaluate(engine, params, mode = 'production')
20
- url = URI.parse("#{@server}/run?e=#{engine}&m=#{mode}")
21
- log("params #{params}")
22
- params = params_mapper(params, engine)
23
- @result = create_request(url, 'POST', params)
24
- response = response_builder
25
- log("response #{response}")
26
- response
27
- end
28
-
29
- def engine_exists(engine)
30
- log("checking if engine (#{engine}) exists")
31
- response = export_engine(engine)
32
- response['body'] = {
33
- 'exists' => !response['body'].empty?
34
- }
35
- response
36
- end
37
-
38
- def get_engine_models(engine)
39
- response = export_engine(engine)
40
- models = !response['body'].empty? ? response['body']['model'] : {}
41
- models_keys = models.keys
42
- models_keys.each do |key|
43
- get_nested_object(models, models[key]['properties'])
44
- end
45
- models
46
- end
47
-
48
- def get_nested_object(models, props)
49
- props.each do |prop|
50
- if prop['typeconcept'] && (prop['typeconcept'].is_a? String)
51
- prop['typeconcept'] = models[prop['typeconcept']]
52
- prop['typeconcept']['properties'] = get_nested_object(models, prop['typeconcept']['properties'])
53
- end
54
- end
55
- end
56
-
57
- private
58
-
59
- def log(message)
60
- @logger.debug("rule engine: #{message}") if @verbose
61
- end
62
-
63
- def valid_json?(obj)
64
- !!JSON.parse(obj)
65
- rescue StandardError
66
- false
67
- end
68
-
69
- def response_hash(code, body, errors)
70
- {
71
- 'code' => code,
72
- 'body' => body,
73
- 'errors' => errors
74
- }
75
- end
76
-
77
- def response_builder
78
- if @time_out
79
- errors = ['HTTP Gateway timeout!']
80
- body = {}
81
- code = 504
82
- elsif @result.code == '502'
83
- errors = ['rule engine server down']
84
- body = {}
85
- code = @result.code
86
- elsif !valid_json?(@result.body)
87
- errors = ['could not parse response body to JSON']
88
- body = {}
89
- code = 500
90
- else
91
- body = JSON.parse(@result.body)
92
- errors = body['errors'] || []
93
- body = body.except('errors', 'status')
94
- code = @result.code
95
- end
96
- response_hash(code, body, errors)
97
- end
98
-
99
- def create_request(url, request_type, params = {})
100
- Timeout.timeout(@request_timeout_in_s) do
101
- http = Net::HTTP.new(url.host, url.port)
102
- http.use_ssl = true if url.instance_of? URI::HTTPS
103
- if request_type == 'GET'
104
- log("Will send get request: #{url}")
105
- request = Net::HTTP::Get.new(url.request_uri)
106
- else
107
- log("Will send post request: #{url}")
108
- request = Net::HTTP::Post.new(url.request_uri)
109
- request.body = params.to_json
110
- log("request body created #{request.body} ")
111
- end
112
- request.basic_auth(@user_name, @password)
113
- request['Content-Type'] = 'application/json'
114
- request['Accept'] = 'application/json'
115
- http.request(request)
116
- end
117
- rescue Timeout::Error
118
- log('HTTP Gateway timeout!')
119
- @time_out = true
120
- end
121
-
122
- def export_engine(engine)
123
- url = URI.parse("#{@server}/engine/export?e=#{engine}")
124
- @result = create_request(url, 'GET')
125
- response_builder
126
- end
127
-
128
- def params_mapper(params, engine)
129
- @models = get_engine_models(engine)
130
- @models_keys = @models.keys
131
- params_keys = params.keys
132
- params_keys.each do |key|
133
- if !@models_keys.include? key
134
- params.delete(key)
135
- else
136
- props = @models[key]['properties'].map do |prop|
137
- prop['name']
138
- end
139
- filter_nested_params(params, key, props)
140
- end
141
- end
142
- log("filtered params #{params}")
143
- params
144
- end
145
-
146
- def filter_nested_params(params, key, props)
147
- keys = params[key].keys
148
- keys.each do |el|
149
- if !props.include? el
150
- params[key].delete(el)
151
- elsif params[key][el].is_a? Hash
152
- nested_el = @models[key]['properties'].find { |obj| obj['name'] == el }
153
- if nested_el['datatype'] != 'object'
154
- params[key].delete(el)
155
- elsif nested_el && !nested_el['typeconcept']['any']
156
- el_props = nested_el['typeconcept']['properties']
157
- filter_nested_params(params[key], el, el_props) if el_props.length
158
- end
159
- end
160
- end
161
- params
162
- end
163
- end
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'timeout'
5
+ require 'digest/md5'
6
+
7
+ # rule engine client class
8
+ class RuleEngineClient
9
+ def initialize(server = 'http://localhost:8088', request_timeout_in_s = 5, verbose = false)
10
+ @server = server
11
+ @verbose = verbose
12
+ @logger = Logger.new($stdout)
13
+ @request_timeout_in_s = request_timeout_in_s
14
+ log("'#{server}' client is initialized")
15
+ end
16
+
17
+ def evaluate(engine, request_body, mode = 'production')
18
+ url = URI.parse("#{@server}/run?e=#{engine}&m=#{mode}")
19
+ request_body = filter_input_for_engine(request_body, engine)
20
+ @result = create_request(url, 'POST', request_body)
21
+ response = response_builder
22
+ response
23
+ end
24
+
25
+ # action is one of [open, commit, rollback]
26
+ def sandbox(action, engine, user)
27
+ url = URI.parse("#{@server}/sandbox/#{action}?e=#{engine}&user=#{user}")
28
+ @result = create_request(url, 'GET')
29
+ response_builder
30
+ end
31
+
32
+ def setup_engine(name, server, username)
33
+ url = URI.parse("#{@server}/setup/engine?name=#{name}&server=#{server}&username=#{username}")
34
+ @result = create_request(url, 'POST')
35
+ response_builder
36
+ end
37
+
38
+ def reload_engine(engine)
39
+ url = URI.parse("#{@server}/engine/reload?e=#{engine}")
40
+ @result = create_request(url, 'GET')
41
+ response_builder
42
+ end
43
+
44
+ def setup_concept(engine, request_body)
45
+ url = URI.parse("#{@server}/setup/concept?e=#{engine}")
46
+ @result = create_request(url, 'POST', request_body)
47
+ response_builder
48
+ end
49
+
50
+ def setup_constant(engine, request_body)
51
+ url = URI.parse("#{@server}/setup/constant?e=#{engine}")
52
+ @result = create_request(url, 'POST', request_body)
53
+ response_builder
54
+ end
55
+
56
+ def setup_switch_rule(engine, request_body)
57
+ url = URI.parse("#{@server}/setup/rule/switch?e=#{engine}")
58
+ @result = create_request(url, 'POST', request_body)
59
+ response_builder
60
+ end
61
+
62
+ def setup_condition_rule(engine, request_body)
63
+ url = URI.parse("#{@server}/setup/rule/condition?e=#{engine}")
64
+ @result = create_request(url, 'POST', request_body)
65
+ response_builder
66
+ end
67
+
68
+ def engine_exists(engine)
69
+ log("checking if engine (#{engine}) exists")
70
+ response = export_engine(engine)
71
+ response['body'] = {
72
+ 'exists' => !response['body'].empty?
73
+ }
74
+ response
75
+ end
76
+
77
+ def get_engine_models(engine)
78
+ response = export_engine(engine)
79
+ models = !response['body'].empty? ? response['body']['model'] : {}
80
+ models_keys = models.keys
81
+ models_keys.each do |key|
82
+ get_nested_object(models, models[key]['properties'])
83
+ end
84
+ models
85
+ end
86
+
87
+ private
88
+
89
+ def get_nested_object(models, props)
90
+ props.each do |prop|
91
+ if prop['typeconcept'] && (prop['typeconcept'].is_a? String)
92
+ prop['typeconcept'] = models[prop['typeconcept']]
93
+ prop['typeconcept']['properties'] = get_nested_object(models, prop['typeconcept']['properties'])
94
+ end
95
+ end
96
+ end
97
+
98
+ def log(message)
99
+ @logger.debug("rule engine: #{message}") if @verbose
100
+ end
101
+
102
+ def valid_json?(obj)
103
+ !!JSON.parse(obj)
104
+ rescue StandardError
105
+ false
106
+ end
107
+
108
+ def response_hash(code, body, errors)
109
+ {
110
+ 'code' => code,
111
+ 'body' => body,
112
+ 'errors' => errors
113
+ }
114
+ end
115
+
116
+ def response_builder
117
+ if @time_out
118
+ errors = ['HTTP Gateway timeout!']
119
+ body = {}
120
+ code = 504
121
+ elsif @result.code == '502'
122
+ errors = ['rule engine server down']
123
+ body = {}
124
+ code = @result.code
125
+ elsif !valid_json?(@result.body)
126
+ errors = ['could not parse response body to JSON']
127
+ body = {}
128
+ code = 500
129
+ else
130
+ body = JSON.parse(@result.body)
131
+ errors = body['errors'] || []
132
+ body = body.except('errors', 'status')
133
+ code = @result.code
134
+ end
135
+ response = response_hash(code, body, errors)
136
+ log("response #{response}")
137
+ response
138
+ end
139
+
140
+ def create_request(url, request_type, body = {})
141
+ Timeout.timeout(@request_timeout_in_s) do
142
+ http = Net::HTTP.new(url.host, url.port)
143
+ http.use_ssl = true if url.instance_of? URI::HTTPS
144
+ if request_type == 'GET'
145
+ log("Will send get request: #{url}")
146
+ request = Net::HTTP::Get.new(url.request_uri)
147
+ else
148
+ log("Will send post request: #{url}")
149
+ request = Net::HTTP::Post.new(url.request_uri)
150
+ request.body = body.to_json
151
+ log("request body created #{request.body}")
152
+ end
153
+ # request.basic_auth(@user_name, @password)
154
+ request['Content-Type'] = 'application/json'
155
+ request['Accept'] = 'application/json'
156
+ http.request(request)
157
+ end
158
+ rescue Timeout::Error
159
+ log('HTTP Gateway timeout!')
160
+ @time_out = true
161
+ end
162
+
163
+ def export_engine(engine)
164
+ url = URI.parse("#{@server}/engine/export?e=#{engine}")
165
+ @result = create_request(url, 'GET')
166
+ response_builder
167
+ end
168
+
169
+ def filter_input_for_engine(request_body, engine)
170
+ log("initial request body: #{request_body}")
171
+ @models = get_engine_models(engine)
172
+ @models_keys = @models.keys
173
+ request_body_keys = request_body.keys
174
+ request_body_keys.each do |key|
175
+ if !@models_keys.include? key
176
+ request_body.delete(key)
177
+ else
178
+ props = @models[key]['properties'].map do |prop|
179
+ prop['name']
180
+ end
181
+ filter_nested_props(request_body, key, props)
182
+ end
183
+ end
184
+ log("filtered request body: #{request_body}")
185
+ request_body
186
+ end
187
+
188
+ def filter_nested_props(request_body, key, props)
189
+ keys = request_body[key].keys
190
+ keys.each do |el|
191
+ if !props.include? el
192
+ request_body[key].delete(el)
193
+ elsif request_body[key][el].is_a? Hash
194
+ nested_el = @models[key]['properties'].find { |obj| obj['name'] == el }
195
+ if nested_el['datatype'] != 'object'
196
+ request_body[key].delete(el)
197
+ elsif nested_el && !nested_el['typeconcept']['any']
198
+ el_props = nested_el['typeconcept']['properties']
199
+ filter_nested_props(request_body[key], el, el_props) if el_props.length
200
+ end
201
+ end
202
+ end
203
+ request_body
204
+ end
205
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rule_engine_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Areej Nour
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2023-01-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: integration with rule server
14
14
  email:
@@ -23,7 +23,7 @@ licenses:
23
23
  - MIT
24
24
  metadata:
25
25
  homepage_uri: https://rubygems.org/gems/rule_engine_client
26
- post_install_message:
26
+ post_install_message:
27
27
  rdoc_options: []
28
28
  require_paths:
29
29
  - lib
@@ -39,7 +39,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
39
  version: '0'
40
40
  requirements: []
41
41
  rubygems_version: 3.3.7
42
- signing_key:
42
+ signing_key:
43
43
  specification_version: 4
44
44
  summary: Rule Engine Client
45
45
  test_files: []