forest_admin_agent 1.2.2 → 1.4.0
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd1bd4933a670f98f7eb6ab7be5f9c07d5a8606e036b5291ccdb2f4ccc63f244
|
4
|
+
data.tar.gz: 22351053a83ac8408274d5bc3db73ebaa340539c2282cd505823a54af3749918
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36ef8ee8a25b96a39899d71aed9600b66098a31715453208563fae25b01a59fb306deeb4fb8734898f47a50bbd5ba74cb359e6807cc9153cc42203a3c4dda38b
|
7
|
+
data.tar.gz: 00e081ae18380f0dcdb589221af21eb0095f4973c3e697b23b2d22db7a1f9f960443e1cfa9758ff762a6ae166b6825cd6312e6bd7e16d671f7d82b489e5e84bb
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'dry-container'
|
2
2
|
require 'filecache'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
module ForestAdminAgent
|
5
6
|
module Builder
|
6
7
|
class AgentFactory
|
7
8
|
include Singleton
|
9
|
+
include ForestAdminAgent::Utils::Schema
|
10
|
+
include ForestAdminDatasourceToolkit::Exceptions
|
8
11
|
|
9
|
-
TTL_CONFIG = 3600
|
10
12
|
TTL_SCHEMA = 7200
|
11
13
|
|
12
14
|
attr_reader :customizer, :container, :has_env_secret
|
@@ -62,16 +64,50 @@ module ForestAdminAgent
|
|
62
64
|
def send_schema(force: false)
|
63
65
|
return unless @has_env_secret
|
64
66
|
|
65
|
-
|
66
|
-
schema_is_know = @container.key?(:schema_file_hash) &&
|
67
|
-
@container.resolve(:schema_file_hash).get('value') == schema[:meta][:schemaFileHash]
|
67
|
+
schema_path = Facades::Container.cache(:schema_path)
|
68
68
|
|
69
|
-
if
|
69
|
+
if Facades::Container.cache(:is_production)
|
70
|
+
unless schema_path && File.exist?(schema_path)
|
71
|
+
raise ForestException, "Can't load #{schema_path}. Providing a schema is mandatory in production."
|
72
|
+
end
|
73
|
+
|
74
|
+
schema = JSON.parse(File.read(schema_path), symbolize_names: true)
|
75
|
+
else
|
76
|
+
generated = SchemaEmitter.generate(@container.resolve(:datasource))
|
77
|
+
meta = SchemaEmitter.meta
|
78
|
+
|
79
|
+
schema = {
|
80
|
+
meta: meta,
|
81
|
+
collections: generated
|
82
|
+
}
|
83
|
+
|
84
|
+
File.write(schema_path, JSON.pretty_generate(schema))
|
85
|
+
end
|
86
|
+
|
87
|
+
if (append_schema_path = Facades::Container.cache(:append_schema_path))
|
88
|
+
begin
|
89
|
+
append_schema_file = JSON.parse(File.read(append_schema_path), symbolize_names: true)
|
90
|
+
schema[:collections] = schema[:collections] + append_schema_file[:collections]
|
91
|
+
rescue StandardError => e
|
92
|
+
raise "Can't load additional schema #{append_schema_path}: #{e.message}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
post_schema(schema, force)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def post_schema(schema, force)
|
102
|
+
api_map = SchemaEmitter.serialize(schema)
|
103
|
+
should_send = do_server_want_schema(api_map[:meta][:schemaFileHash])
|
104
|
+
|
105
|
+
if should_send || force
|
70
106
|
client = ForestAdminAgent::Http::ForestAdminApiRequester.new
|
71
|
-
client.post('/forest/apimaps',
|
107
|
+
client.post('/forest/apimaps', api_map.to_json)
|
72
108
|
schema_file_hash_cache = FileCache.new('app', @options[:cache_dir].to_s, TTL_SCHEMA)
|
73
109
|
schema_file_hash_cache.get_or_set 'value' do
|
74
|
-
|
110
|
+
api_map[:meta][:schemaFileHash]
|
75
111
|
end
|
76
112
|
@container.register(:schema_file_hash, schema_file_hash_cache)
|
77
113
|
ForestAdminAgent::Facades::Container.logger.log('Info', 'schema was updated, sending new version')
|
@@ -81,7 +117,19 @@ module ForestAdminAgent
|
|
81
117
|
end
|
82
118
|
end
|
83
119
|
|
84
|
-
|
120
|
+
def do_server_want_schema(hash)
|
121
|
+
client = ForestAdminAgent::Http::ForestAdminApiRequester.new
|
122
|
+
|
123
|
+
begin
|
124
|
+
response = client.post('/forest/apimaps/hashcheck', { schemaFileHash: hash }.to_json)
|
125
|
+
body = JSON.parse(response.body)
|
126
|
+
body['sendSchema']
|
127
|
+
rescue JSON::ParserError
|
128
|
+
raise ForestException, "Invalid JSON response from ForestAdmin server #{response.body}"
|
129
|
+
rescue Faraday::Error => e
|
130
|
+
client.handle_response_error(e)
|
131
|
+
end
|
132
|
+
end
|
85
133
|
|
86
134
|
def build_container
|
87
135
|
@container = Dry::Container.new
|
@@ -6,104 +6,69 @@ module ForestAdminAgent
|
|
6
6
|
module Schema
|
7
7
|
class SchemaEmitter
|
8
8
|
LIANA_NAME = "agent-ruby"
|
9
|
+
LIANA_VERSION = "1.4.0"
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if Facades::Container.cache(:is_production)
|
15
|
-
schema = if schema_path && File.exist?(schema_path)
|
16
|
-
JSON.parse(File.read(schema_path), { symbolize_names: true })
|
17
|
-
else
|
18
|
-
ForestAdminAgent::Facades::Container.logger.log(
|
19
|
-
'Warn',
|
20
|
-
'The .forestadmin-schema.json file doesn\'t exist'
|
21
|
-
)
|
22
|
-
|
23
|
-
{
|
24
|
-
meta: meta(Digest::SHA1.hexdigest('')),
|
25
|
-
collections: {}
|
26
|
-
}
|
27
|
-
end
|
28
|
-
else
|
29
|
-
schema = generate(datasource)
|
30
|
-
hash = Digest::SHA1.hexdigest(schema.to_json)
|
31
|
-
schema = {
|
32
|
-
meta: meta(hash),
|
33
|
-
collections: schema
|
34
|
-
}
|
35
|
-
|
36
|
-
File.write(schema_path, JSON.pretty_generate(schema))
|
37
|
-
end
|
38
|
-
|
39
|
-
serialize(schema)
|
11
|
+
def self.generate(datasource)
|
12
|
+
datasource.collections
|
13
|
+
.map { |_name, collection| GeneratorCollection.build_schema(collection) }
|
14
|
+
.sort_by { |collection| collection[:name] }
|
40
15
|
end
|
41
16
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
def meta(hash)
|
52
|
-
{
|
53
|
-
liana: LIANA_NAME,
|
54
|
-
liana_version: LIANA_VERSION,
|
55
|
-
stack: {
|
56
|
-
engine: 'ruby',
|
57
|
-
engine_version: RUBY_VERSION
|
58
|
-
},
|
59
|
-
schemaFileHash: hash
|
17
|
+
def self.meta
|
18
|
+
{
|
19
|
+
liana: LIANA_NAME,
|
20
|
+
liana_version: LIANA_VERSION,
|
21
|
+
stack: {
|
22
|
+
engine: 'ruby',
|
23
|
+
engine_version: RUBY_VERSION
|
60
24
|
}
|
61
|
-
|
62
|
-
|
63
|
-
def serialize(schema)
|
64
|
-
data = []
|
65
|
-
included = []
|
66
|
-
schema[:collections].each do |collection|
|
67
|
-
collection_actions = collection[:actions]
|
68
|
-
collection_segments = collection[:segments]
|
69
|
-
|
70
|
-
collection.delete(:actions)
|
71
|
-
collection.delete(:segments)
|
72
|
-
|
73
|
-
included << get_smart_features_by_collection('actions', collection_actions, with_attributes: true)
|
74
|
-
included << get_smart_features_by_collection('segments', collection_segments, with_attributes: true)
|
25
|
+
}
|
26
|
+
end
|
75
27
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
28
|
+
def self.serialize(schema)
|
29
|
+
hash = Digest::SHA1.hexdigest(schema[:collections].to_json)
|
30
|
+
data = []
|
31
|
+
included = []
|
32
|
+
schema[:collections].each do |collection|
|
33
|
+
collection_actions = collection[:actions]
|
34
|
+
collection_segments = collection[:segments]
|
35
|
+
|
36
|
+
collection.delete(:actions)
|
37
|
+
collection.delete(:segments)
|
38
|
+
|
39
|
+
included << get_smart_features_by_collection('actions', collection_actions, with_attributes: true)
|
40
|
+
included << get_smart_features_by_collection('segments', collection_segments, with_attributes: true)
|
41
|
+
|
42
|
+
data.push(
|
43
|
+
{
|
44
|
+
id: collection[:name],
|
45
|
+
type: 'collections',
|
46
|
+
attributes: collection,
|
47
|
+
relationships: {
|
48
|
+
actions: { data: get_smart_features_by_collection('actions', collection_actions) },
|
49
|
+
segments: { data: get_smart_features_by_collection('segments', collection_segments) }
|
85
50
|
}
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
{
|
90
|
-
data: data,
|
91
|
-
included: included.reject!(&:empty?)&.flatten || [],
|
92
|
-
meta: schema[:meta]
|
93
|
-
}
|
51
|
+
}
|
52
|
+
)
|
94
53
|
end
|
95
54
|
|
96
|
-
|
97
|
-
|
55
|
+
{
|
56
|
+
data: data,
|
57
|
+
included: included.reject!(&:empty?)&.flatten || [],
|
58
|
+
meta: schema[:meta].merge(schemaFileHash: hash)
|
59
|
+
}
|
60
|
+
end
|
98
61
|
|
99
|
-
|
100
|
-
|
101
|
-
smart_feature[:attributes] = value if with_attributes
|
102
|
-
smart_features << smart_feature
|
103
|
-
end
|
62
|
+
def self.get_smart_features_by_collection(type, data, with_attributes: false)
|
63
|
+
smart_features = []
|
104
64
|
|
105
|
-
|
65
|
+
data.each do |value|
|
66
|
+
smart_feature = { id: value[:id], type: type }
|
67
|
+
smart_feature[:attributes] = value if with_attributes
|
68
|
+
smart_features << smart_feature
|
106
69
|
end
|
70
|
+
|
71
|
+
smart_features
|
107
72
|
end
|
108
73
|
end
|
109
74
|
end
|