trophonius 1.4.5.5 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eecfcdce6515f91456cd8e482da0eec5104f2e8fde6b3625baf0db732bc12969
4
- data.tar.gz: 6b79cbc8b44fe728171a3123d12def4f4df2eaf8f43c66b8201564ed14e12cae
3
+ metadata.gz: 386e8ae48aba1dd8e6898dcbc16dde02e4acd506658676a146ddc646d96d2929
4
+ data.tar.gz: 59c8f91b771e3175347f9fa6fc87b522878e3c2cb9f1cb468f3a78b7cf85c616
5
5
  SHA512:
6
- metadata.gz: a048ab92bfc7971e9d0f80a33e45ba7dc689cbff9d711863cdc5aa0308b29bec48412d9bda6adacb38e267b552a0345a6eb3f8214fa383ecacaaabcf8410db20
7
- data.tar.gz: 885bee6b19febf90d566c64b7e2fc714d9323efabe10bc0a47fab0a10ae823aec84b5935a3555834e83363e9378322314f2623c727bba1dde2c48d302971c8ad
6
+ metadata.gz: beca517abee0fd0db44a9e1cc96f16a5014e061101b8818aaa7f368ac597eecff3aaf4968f3ddd063732a2df36f7c8fa841d322b46599062b0a45b57887ae0d3
7
+ data.tar.gz: 71b436a45681c37c4bd6b8f3ce34d35e0cb11badb4356a32b2f1be8ebf7eb29af21c88e51a41d5166f2762bee0af4773a628d28f0cd1f7371ab7c45bc4873d24
@@ -1,7 +1,12 @@
1
+ # require 'time'
2
+ # require 'date_time'
3
+ # require 'date'
4
+
1
5
  require 'active_support/configurable'
6
+ require 'ethon'
2
7
 
3
8
  module Trophonius
4
- class Trophonius::Configuration # :nodoc:
9
+ class Configuration # :nodoc:
5
10
  include ActiveSupport::Configurable
6
11
 
7
12
  config_accessor(:host) { '127.0.0.1' }
@@ -13,15 +18,16 @@ module Trophonius
13
18
  config_accessor(:username) { 'Admin' }
14
19
  config_accessor(:password) { '' }
15
20
  config_accessor(:ssl) { true }
16
- config_accessor(:fm_18) { false }
21
+ config_accessor(:fm_18) { true }
17
22
  config_accessor(:count_result_script) { '' }
18
23
  config_accessor(:layout_name) { '' }
19
24
  config_accessor(:non_modifiable_fields) { [] }
20
- config_accessor(:all_fields) { {} }
21
25
  config_accessor(:translations) { {} }
22
26
  config_accessor(:has_many_relations) { {} }
23
27
  config_accessor(:belongs_to_relations) { {} }
24
28
  config_accessor(:local_network) { false }
25
29
  config_accessor(:redis_connection) { false }
30
+ config_accessor(:pool_size) { 5 }
31
+ config_accessor(:debug) { false }
26
32
  end
27
33
  end
@@ -1,15 +1,37 @@
1
1
  require 'time'
2
2
  require 'base64'
3
- require 'typhoeus'
4
- require 'trophonius_redis_manager'
3
+ require 'securerandom'
4
+ require 'connectors/redis_manager'
5
+
5
6
  module Trophonius
6
- module Trophonius::Connection
7
+ class Connection
8
+ attr_reader :id
9
+
10
+ def initialize
11
+ @id = SecureRandom.uuid
12
+ @token = ''
13
+ connect
14
+ end
15
+
16
+ ##
17
+ # Returns the last received token
18
+ # @return [String] the last valid *token* used to connect with the FileMaker data api
19
+ def token
20
+ if valid_connection?
21
+ Trophonius.config.redis_connection ? Trophonius::RedisManager.get_key(key: 'token') : @token
22
+ else
23
+ connect
24
+ end
25
+ end
26
+
27
+ private
28
+
7
29
  ##
8
30
  # Creates a new connection to FileMaker
9
31
  #
10
32
  # @return [String] the *token* used to connect with the FileMaker data api
11
33
 
12
- def self.connect
34
+ def connect
13
35
  if Trophonius.config.redis_connection
14
36
  Trophonius::RedisManager.set_key(key: 'token', value: setup_connection)
15
37
  Trophonius::RedisManager.set_key(key: 'last_connection', value: Time.now)
@@ -21,20 +43,40 @@ module Trophonius
21
43
  end
22
44
  end
23
45
 
24
- ##
25
- # Creates and runs a HTTP request to create a new data api connection
26
- # This method throws an error when the request returns with a HTTP error or a FileMaker error
27
- # @return [String] the *token* used to connect with the FileMaker data api if successful
28
-
29
- def self.setup_connection
46
+ def reset_token
30
47
  if Trophonius.config.redis_connection
31
48
  Trophonius::RedisManager.set_key(key: 'token', value: '')
32
49
  Trophonius::RedisManager.set_key(key: 'last_connection', value: nil)
33
50
  else
34
51
  @token = ''
52
+ @last_connection = nil
35
53
  end
36
- ssl_verifyhost = Trophonius.config.local_network ? 0 : 2
37
- ssl_verifypeer = !Trophonius.config.local_network
54
+ end
55
+
56
+ def fm_external_data_source
57
+ if Trophonius.config.external_name.empty?
58
+ {}
59
+ else
60
+ {
61
+ fmDataSource: [
62
+ {
63
+ database: Trophonius.config.external_name,
64
+ username: Trophonius.config.external_username,
65
+ password: Trophonius.config.external_password
66
+ }
67
+ ]
68
+ }.to_json
69
+ end
70
+ end
71
+
72
+ ##
73
+ # Creates and runs a HTTP request to create a new data api connection
74
+ # This method throws an error when the request returns with a HTTP error or a FileMaker error
75
+ # @return [String] the *token* used to connect with the FileMaker data api if successful
76
+
77
+ def setup_connection
78
+ reset_token
79
+
38
80
  uri = URI::RFC2396_Parser.new
39
81
  url =
40
82
  URI(
@@ -42,24 +84,13 @@ module Trophonius
42
84
  "http#{Trophonius.config.ssl == true ? 's' : ''}://#{Trophonius.config.host}/fmi/data/v1/databases/#{Trophonius.config.database}/sessions"
43
85
  )
44
86
  )
87
+ ssl_verifyhost = Trophonius.config.local_network ? 0 : 2
88
+ ssl_verifypeer = !Trophonius.config.local_network
45
89
  request =
46
90
  Typhoeus::Request.new(
47
91
  url,
48
92
  method: :post,
49
- body:
50
- if Trophonius.config.external_name.empty?
51
- {}
52
- else
53
- {
54
- fmDataSource: [
55
- {
56
- database: Trophonius.config.external_name,
57
- username: Trophonius.config.external_username,
58
- password: Trophonius.config.external_password
59
- }
60
- ]
61
- }.to_json
62
- end,
93
+ body: fm_external_data_source,
63
94
  params: {},
64
95
  ssl_verifyhost: ssl_verifyhost,
65
96
  ssl_verifypeer: ssl_verifypeer,
@@ -70,12 +101,10 @@ module Trophonius
70
101
  )
71
102
  temp = request.run
72
103
  body = temp.response_body
73
- headers = temp.headers
74
- code = temp.code
75
104
 
76
105
  begin
77
106
  parsed = JSON.parse(body)
78
- rescue Exception => e
107
+ rescue StandardError => e
79
108
  puts e
80
109
  puts e.backtrace
81
110
  Error.throw_error('1631')
@@ -87,7 +116,7 @@ module Trophonius
87
116
  ##
88
117
  # Disconnects from the FileMaker server
89
118
  #
90
- def self.disconnect
119
+ def disconnect
91
120
  uri = URI::RFC2396_Parser.new
92
121
  url =
93
122
  URI(
@@ -113,7 +142,9 @@ module Trophonius
113
142
 
114
143
  begin
115
144
  parsed = JSON.parse(temp.response_body)
116
- rescue Exception => e
145
+ rescue StandardError => e
146
+ puts e
147
+ puts e.backtrace
117
148
  Error.throw_error('1631')
118
149
  end
119
150
  Error.throw_error(parsed['messages'][0]['code']) if parsed['messages'][0]['code'] != '0'
@@ -123,17 +154,10 @@ module Trophonius
123
154
  true
124
155
  end
125
156
 
126
- ##
127
- # Returns the last received token
128
- # @return [String] the last valid *token* used to connect with the FileMaker data api
129
- def self.token
130
- Trophonius.config.redis_connection ? Trophonius::RedisManager.get_key(key: 'token') : @token
131
- end
132
-
133
157
  ##
134
158
  # Returns the receive time of the last received token
135
159
  # @return [Time] Returns the receive time of the last received token
136
- def self.last_connection
160
+ def last_connection
137
161
  last = Trophonius.config.redis_connection ? Trophonius::RedisManager.get_key(key: 'last_connection') : nil
138
162
  last = last.nil? ? nil : Time.parse(last)
139
163
  Trophonius.config.redis_connection ? last : @last_connection
@@ -142,37 +166,23 @@ module Trophonius
142
166
  ##
143
167
  # Tests whether the FileMaker token is still valid
144
168
  # @return [Boolean] True if the token is valid False if invalid
145
- def self.test_connection
146
- uri = URI::RFC2396_Parser.new
147
- url =
148
- URI(
149
- uri.escape(
150
- "http#{Trophonius.config.ssl == true ? 's' : ''}://#{Trophonius.config.host}/fmi/data/v1/databases/#{
151
- Trophonius.config.database
152
- }/layouts/#{Trophonius.config.layout_name}/records?_limit=1"
153
- )
154
- )
155
- begin
156
- request =
157
- Typhoeus::Request.new(
158
- url,
159
- method: :get, body: {}, params: {}, headers: { 'Content-Type' => 'application/json', Authorization: "Bearer #{token}" }
160
- )
161
- temp = request.run
162
- json_parsed = JSON.parse(temp.response_body)
169
+ def test_connection
170
+ return last_connection.nil? || last_connection < Time.now - (15 * 60) if Trophonius.config.layout_name == ''
163
171
 
164
- json_parsed['messages'][0]['code'] == '0'
165
- rescue StandardError => e
166
- puts e
167
- puts e.backtrace
168
- false
169
- end
172
+ path = "/layouts/#{Trophonius.config.layout_name}/records?_limit=1"
173
+ response =
174
+ Trophonius::DatabaseRequest.make_request(path, :get, {}, bypass_queue_with: "Bearer #{@token}")
175
+ response['messages'][0]['code'] == '0'
176
+ rescue StandardError => e
177
+ puts e
178
+ puts e.backtrace
179
+ false
170
180
  end
171
181
 
172
182
  ##
173
183
  # Returns whether the current connection is still valid
174
184
  # @return [Boolean] True if the connection is valid False if invalid
175
- def self.valid_connection?
185
+ def valid_connection?
176
186
  if Trophonius.config.layout_name != '' && test_connection == false
177
187
  false
178
188
  else
@@ -0,0 +1,31 @@
1
+ module Trophonius
2
+ class ConnectionManager
3
+ def initialize
4
+ @connections = {}
5
+ Trophonius.config.pool_size.times do
6
+ connection = Connection.new
7
+ @connections[connection.id] = { connection: connection, queue: [] }
8
+ end
9
+ end
10
+
11
+ def enqueue(id)
12
+ connection = @connections.values.min_by { |c| c[:queue].length }
13
+ connection[:queue].push(id)
14
+ puts "in,#{connection[:connection].id},#{connection[:connection].token},#{connection[:queue].length}" if Trophonius.config.debug == true
15
+ auth_header_bearer(connection[:connection].id)
16
+ end
17
+
18
+ def dequeue(id)
19
+ connection = @connections.values.find { |c| c[:queue].include?(id) }
20
+ connection[:queue].delete_if { |q_id| q_id == id }
21
+ puts "out,#{connection[:connection].id},#{connection[:connection].token},#{connection[:queue].length}" if Trophonius.config.debug == true
22
+ nil
23
+ end
24
+
25
+ private
26
+
27
+ def auth_header_bearer(id)
28
+ "Bearer #{@connections.dig(id, :connection).token}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'connectors/connection_manager'
5
+ require 'debug_printer'
6
+ require 'typhoeus'
7
+ require 'uri'
8
+ require 'securerandom'
9
+ require 'net/http'
10
+
11
+ module Trophonius
12
+ module DatabaseRequest
13
+ include DebugPrinter
14
+ ##
15
+ # Crafts and runs a HTTP request of any type
16
+ #
17
+ # @param [URI] url_path: the url to make the request to
18
+ #
19
+ # @param [String] method: the type of HTTP request to make (i.e. get)
20
+ #
21
+ # @param [JSONString] body: the body of the HTTP request
22
+ #
23
+ # @param [String] params: optional parameters added to the request
24
+ #
25
+ # @param [String] bypass_queue_with: optional way to bypass the ConnectionManager
26
+ #
27
+ # @return [JSON] parsed json of the response
28
+ def self.make_request(url_path, method, body, params = '', bypass_queue_with: '')
29
+ ssl_verifyhost = Trophonius.config.local_network ? 0 : 2
30
+ ssl_verifypeer = !Trophonius.config.local_network
31
+ base_url = "http#{Trophonius.config.ssl == true ? 's' : ''}://#{Trophonius.config.host}/fmi/data/v1/databases/#{Trophonius.config.database}"
32
+ uri = URI::RFC2396_Parser.new
33
+ url =
34
+ URI(
35
+ uri.escape("#{base_url}/#{url_path}")
36
+ )
37
+
38
+ id = SecureRandom.uuid
39
+ auth = bypass_queue_with.empty? ? auth_header_bearer(id) : bypass_queue_with
40
+
41
+ request =
42
+ Typhoeus::Request.new(
43
+ url,
44
+ method: method.to_sym,
45
+ body: body,
46
+ params: params,
47
+ ssl_verifyhost: ssl_verifyhost,
48
+ ssl_verifypeer: ssl_verifypeer,
49
+ headers: { 'Content-Type' => 'application/json', Authorization: auth }
50
+ )
51
+
52
+ DebugPrinter.print_debug('USED URL', url)
53
+ DebugPrinter.print_debug('SENT BODY', body)
54
+
55
+ temp = request.run
56
+
57
+ Trophonius.connection_manager.dequeue(id) if bypass_queue_with.empty?
58
+
59
+ begin
60
+ response_body = JSON.parse(temp.response_body)
61
+ DebugPrinter.print_debug('RECEIVED BODY', JSON.pretty_generate(response_body))
62
+ response_body
63
+ rescue StandardError => e
64
+ puts e
65
+ puts e.backtrace
66
+ Error.throw_error('1631')
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Crafts and runs a HTTP request for uploading a file to a container
72
+ #
73
+ # @param [URI] urlparam: the url to make the request to
74
+ #
75
+ # @param [String] auth: the authentication required for the request
76
+ #
77
+ # @param [Tempfile or File] file: file to upload
78
+ #
79
+ # @return [JSON] parsed json of the response
80
+ def self.upload_file_request(url_param, file)
81
+ base_url = "http#{Trophonius.config.ssl == true ? 's' : ''}://#{Trophonius.config.host}/fmi/data/v1/databases/#{Trophonius.config.database}"
82
+ url = URI("#{base_url}/#{url_param}")
83
+
84
+ https = Net::HTTP.new(url.host, url.port)
85
+ https.use_ssl = true
86
+
87
+ id = SecureRandom.uuid
88
+ request = Net::HTTP::Post.new(url)
89
+ request['Authorization'] = auth_header_bearer(id)
90
+ request['Content-Type'] = 'multipart/form-data;'
91
+ form_data = [['upload', file]]
92
+ request.set_form form_data, 'multipart/form-data'
93
+ response = https.request(request)
94
+ Trophonius.connection_manager.dequeue(id)
95
+ begin
96
+ JSON.parse(response.read_body)
97
+ rescue StandardError
98
+ Error.throw_error('1631')
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Gets a valid auth header containing the access token
104
+ #
105
+ # @return [String] a valid auth header containing the access token
106
+ def self.auth_header_bearer(id)
107
+ Trophonius.connection_manager.enqueue(id)
108
+ end
109
+
110
+ ##
111
+ # Retrieves the first record from FileMaker
112
+ #
113
+ # @return [JSON] The first record from FileMaker
114
+ def self.retrieve_first(layout_name)
115
+ make_request("layouts/#{layout_name}/records?_limit=1", 'get', '{}')
116
+ end
117
+
118
+ ##
119
+ # Retrieves the fieldnames of a layout
120
+ #
121
+ # @return [JSON] The fieldnames of a layout
122
+ def self.get_layout_field_names(layout_name)
123
+ make_request("layouts/#{layout_name}", 'get', '{}')['response']['fieldMetaData'].map { |field| field['name'] }
124
+ rescue StandardError => e
125
+ puts e
126
+ puts e.backtrace
127
+ Error.throw_error('1631')
128
+ end
129
+
130
+ ##
131
+ # Runs a FileMaker script
132
+ #
133
+ # @return [JSON] The script result from FileMaker
134
+ def self.run_script(script, scriptparameter, layout_name)
135
+ make_request("/layouts/#{layout_name}/records?_limit=1&script=#{script}&script.param=#{scriptparameter}", 'get', '{}')
136
+ end
137
+
138
+ ##
139
+ # Retrieves the 10000000 records from FileMaker
140
+ #
141
+ # @return [JSON] The first 10000000 records from FileMaker
142
+ def self.retrieve_all(layout_name, sort)
143
+ path = "layouts/#{layout_name}/records?_limit=10000000#{
144
+ Trophonius.config.count_result_script == '' ? '' : "&script=#{Trophonius.config.count_result_script}"
145
+ }"
146
+ path += "&_sort=#{sort_order}" if sort.present?
147
+ path += "&script=#{Trophonius.config.count_result_script}" if Trophonius.config.count_result_script.present?
148
+ make_request(path, 'get', '{}')
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,11 @@
1
+ module Trophonius
2
+ module DebugPrinter
3
+ def self.print_debug(open_close_message, message)
4
+ return unless Trophonius.config.debug == true
5
+
6
+ puts "======== #{open_close_message} ========"
7
+ puts message
8
+ puts "======== #{open_close_message} ========"
9
+ end
10
+ end
11
+ end
@@ -1,8 +1,8 @@
1
1
  require 'json'
2
- require 'trophonius_config'
2
+ require 'config'
3
3
 
4
4
  module Trophonius
5
- module Trophonius::Error
5
+ module Error
6
6
  class RecordNotFoundError < StandardError; end # :nodoc:
7
7
  class FieldUnexistingError < NoMethodError; end # :nodoc:
8
8
  class ScriptUnexistingError < NoMethodError; end # :nodoc:
@@ -89,7 +89,7 @@ module Trophonius
89
89
  when '101'
90
90
  raise RecordNotFoundError.new, "Record #{more_info} was not found"
91
91
  when '102'
92
- raise FieldUnexistingError.new, 'Field does not exist' if more_info.zero?
92
+ raise FieldUnexistingError.new, 'Field does not exist' if more_info.is_a?(Integer) && more_info.zero?
93
93
 
94
94
  raise FieldUnexistingError.new, "Following field(s) #{more_info} do not exist on layout #{layout_info}"
95
95
  when '103'
@@ -1,6 +1,6 @@
1
1
  class Date
2
2
  def to_fm
3
- self.strftime('%m/%d/%Y')
3
+ strftime('%m/%d/%Y')
4
4
  end
5
5
 
6
6
  def self.from_fm(fm_date)
data/lib/fm_time.rb ADDED
@@ -0,0 +1,11 @@
1
+ class Time
2
+ def to_fm
3
+ strftime('%m-%d-%Y %H:%M:%S')
4
+ end
5
+
6
+ def self.from_fm(time)
7
+ Time.strptime(time, '%m/%d/%Y %H:%M:%S')
8
+ end
9
+
10
+ alias convert_to_fm to_fm
11
+ end
@@ -22,6 +22,7 @@ module Trophonius
22
22
  config.password = Rails.application.credentials.dig(:password) # (requires >= Rails 5.2) otherwise use old secrets
23
23
  config.redis_connection = false # default false, true if you want to store the token in redis
24
24
  config.ssl = true # or false depending on whether https or http should be used
25
+ config.fm_18 = true
25
26
  # USE THE NEXT OPTION WITH CAUTION
26
27
  config.local_network = false # if true the ssl certificate will not be verified to allow for self-signed certificates
27
28
  end"