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.
- checksums.yaml +4 -4
- data/lib/rule_engine_client.rb +205 -163
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6698e5437993a11e71039e2c8b98050d8cd3784e2efcc1cacb72220cddf4528d
|
4
|
+
data.tar.gz: 7d5aa87bd97116c920811330a216140dee70efc3e3dfeb73b36bd0ba4efcc79a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a7bfcde500e54a62845534f633841fefca67f66b71ee284a8af6e9d6bba1f14d46f710674dee502a2bc8d999ec0173db832c92abcc311ed7f8ac2e7db1ddb98
|
7
|
+
data.tar.gz: 99642690f3a3885c1401d3bdf3af99092c03af8d84c899dbddbd388752babbbc3e325bafb1861fe2a41a8c59804c0eada86a070339743a18ac77632a61bfebc6
|
data/lib/rule_engine_client.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
'
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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.
|
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:
|
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: []
|