trophonius 1.4.5.5 → 2.1

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: 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"