forest_admin_agent 1.2.1 → 1.3.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: 003b5794d0fe2ed43b703cbcb42fa042007533c9437fdb4490ecea7a66d38e93
4
- data.tar.gz: 447548e96498ec5393edc1d4c9620b1ceefb58f90e367040afb93971bfd2cd2e
3
+ metadata.gz: da8a8b740883c3c1ec638f1751ea49b801a1c558a92f900c9b3f22360f66410c
4
+ data.tar.gz: f12e6b0fb89390576841467edf90a825fbeae079198d3b19b6099e311fbc05f6
5
5
  SHA512:
6
- metadata.gz: 30c15c87c87e621428615cd99af9791f37a42184a9a5e5f1900b071765fe35c2d90057077a8f91ee2323d89bcb95d27f3fd85df97873959e667d772cc5865019
7
- data.tar.gz: ad3e5631354565adaa1c2989219f4a993567ad942f2ef199c229a0be476e80be38fa07f597ec064bea3bba28828976a9f441d0a98ded332c6a2423a2a20e7768
6
+ metadata.gz: '008e1c6e1b6df55fbdd977ef91d1b028c28d74c43e9e2fb4223ceb266ba742625b23c248746875270e0330542146035cf359abe2860177ae6cd649ae1535fc3d'
7
+ data.tar.gz: 1831488afd41a4ef2d390ca1f12c4b559f710ffa88afd7c3ebc684794c7b1cc7fdeda43cd5055a4c90fe9138eb367ec5a06aa6f09f1fdf156f08c732b8a27711
@@ -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
- schema = ForestAdminAgent::Utils::Schema::SchemaEmitter.get_serialized_schema(@container.resolve(:datasource))
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 !schema_is_know || force
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', schema.to_json)
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
- schema[:meta][:schemaFileHash]
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
- private
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
@@ -2,10 +2,9 @@ module ForestAdminAgent
2
2
  module Http
3
3
  module Exceptions
4
4
  class AuthenticationOpenIdClient < HttpException
5
- def initialize(status = 401,
6
- message = 'Authentication failed with OpenID Client',
5
+ def initialize(message = 'Authentication failed with OpenID Client',
7
6
  name = 'AuthenticationOpenIdClient')
8
- super
7
+ super(401, message, name)
9
8
  end
10
9
  end
11
10
  end
@@ -1,13 +1,9 @@
1
1
  module ForestAdminAgent
2
2
  module Http
3
3
  module Exceptions
4
- class NotFoundError < StandardError
5
- attr_reader :name, :status
6
-
7
- def initialize(msg, name = 'NotFoundError')
8
- super(msg)
9
- @name = name
10
- @status = 404
4
+ class NotFoundError < HttpException
5
+ def initialize(message, name = 'NotFoundError')
6
+ super(404, message, name)
11
7
  end
12
8
  end
13
9
  end
@@ -42,9 +42,8 @@ module ForestAdminAgent
42
42
 
43
43
  def handle_authentication_callback(args = {})
44
44
  if args[:params].key?(:error)
45
- raise AuthenticationOpenIdClient.new(args[:params][:state],
46
- args[:params][:error],
47
- args[:params][:error_description])
45
+ raise AuthenticationOpenIdClient.new(args[:params][:error_description] || args[:params][:error],
46
+ args[:params][:error])
48
47
  end
49
48
 
50
49
  if args.dig(:headers, 'action_dispatch.remote_ip')
@@ -6,104 +6,69 @@ module ForestAdminAgent
6
6
  module Schema
7
7
  class SchemaEmitter
8
8
  LIANA_NAME = "agent-ruby"
9
+ LIANA_VERSION = "1.3.0"
9
10
 
10
- LIANA_VERSION = "1.2.1"
11
-
12
- def self.get_serialized_schema(datasource)
13
- schema_path = Facades::Container.cache(:schema_path)
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
- class << self
43
- private
44
-
45
- def generate(datasource)
46
- datasource.collections
47
- .map { |_name, collection| GeneratorCollection.build_schema(collection) }
48
- .sort_by { |collection| collection[:name] }
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
- end
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
- data.push(
77
- {
78
- id: collection[:name],
79
- type: 'collections',
80
- attributes: collection,
81
- relationships: {
82
- actions: { data: get_smart_features_by_collection('actions', collection_actions) },
83
- segments: { data: get_smart_features_by_collection('segments', collection_segments) }
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
- end
88
-
89
- {
90
- data: data,
91
- included: included.reject!(&:empty?)&.flatten || [],
92
- meta: schema[:meta]
93
- }
51
+ }
52
+ )
94
53
  end
95
54
 
96
- def get_smart_features_by_collection(type, data, with_attributes: false)
97
- smart_features = []
55
+ {
56
+ data: data,
57
+ included: included.reject!(&:empty?)&.flatten || [],
58
+ meta: schema[:meta].merge(schemaFileHash: hash)
59
+ }
60
+ end
98
61
 
99
- data.each do |value|
100
- smart_feature = { id: value[:id], type: type }
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
- smart_features
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
@@ -1,3 +1,3 @@
1
1
  module ForestAdminAgent
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu